Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F15465230
D20269.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
41 KB
Referenced Files
None
Subscribers
None
D20269.diff
View Options
diff --git a/resources/celerity/map.php b/resources/celerity/map.php
--- a/resources/celerity/map.php
+++ b/resources/celerity/map.php
@@ -408,14 +408,14 @@
'rsrc/js/application/phortune/phortune-credit-card-form.js' => 'd12d214f',
'rsrc/js/application/policy/behavior-policy-control.js' => '0eaa33a9',
'rsrc/js/application/policy/behavior-policy-rule-editor.js' => '9347f172',
- 'rsrc/js/application/projects/WorkboardBoard.js' => '2181739b',
- 'rsrc/js/application/projects/WorkboardCard.js' => 'bc92741f',
- 'rsrc/js/application/projects/WorkboardCardTemplate.js' => 'b0b5f90a',
- 'rsrc/js/application/projects/WorkboardColumn.js' => '6461f58b',
+ 'rsrc/js/application/projects/WorkboardBoard.js' => 'fc1664ff',
+ 'rsrc/js/application/projects/WorkboardCard.js' => '0392a5d8',
+ 'rsrc/js/application/projects/WorkboardCardTemplate.js' => '2a61f8d4',
+ 'rsrc/js/application/projects/WorkboardColumn.js' => '533dd592',
'rsrc/js/application/projects/WorkboardController.js' => '42c7a5a7',
- 'rsrc/js/application/projects/WorkboardHeader.js' => '6e75daea',
- 'rsrc/js/application/projects/WorkboardHeaderTemplate.js' => '2d641f7d',
- 'rsrc/js/application/projects/behavior-project-boards.js' => 'cca3f5f8',
+ 'rsrc/js/application/projects/WorkboardHeader.js' => '111bfd2d',
+ 'rsrc/js/application/projects/WorkboardHeaderTemplate.js' => 'b65351bd',
+ 'rsrc/js/application/projects/behavior-project-boards.js' => '285c337a',
'rsrc/js/application/projects/behavior-project-create.js' => '34c53422',
'rsrc/js/application/projects/behavior-reorder-columns.js' => '8ac32fd9',
'rsrc/js/application/releeph/releeph-preview-branch.js' => '75184d68',
@@ -656,7 +656,7 @@
'javelin-behavior-phuix-example' => 'c2c500a7',
'javelin-behavior-policy-control' => '0eaa33a9',
'javelin-behavior-policy-rule-editor' => '9347f172',
- 'javelin-behavior-project-boards' => 'cca3f5f8',
+ 'javelin-behavior-project-boards' => '285c337a',
'javelin-behavior-project-create' => '34c53422',
'javelin-behavior-quicksand-blacklist' => '5a6f6a06',
'javelin-behavior-read-only-warning' => 'b9109f8f',
@@ -728,13 +728,13 @@
'javelin-view-renderer' => '9aae2b66',
'javelin-view-visitor' => '308f9fe4',
'javelin-websocket' => 'fdc13e4e',
- 'javelin-workboard-board' => '2181739b',
- 'javelin-workboard-card' => 'bc92741f',
- 'javelin-workboard-card-template' => 'b0b5f90a',
- 'javelin-workboard-column' => '6461f58b',
+ 'javelin-workboard-board' => 'fc1664ff',
+ 'javelin-workboard-card' => '0392a5d8',
+ 'javelin-workboard-card-template' => '2a61f8d4',
+ 'javelin-workboard-column' => '533dd592',
'javelin-workboard-controller' => '42c7a5a7',
- 'javelin-workboard-header' => '6e75daea',
- 'javelin-workboard-header-template' => '2d641f7d',
+ 'javelin-workboard-header' => '111bfd2d',
+ 'javelin-workboard-header-template' => 'b65351bd',
'javelin-workflow' => '958e9045',
'maniphest-report-css' => '3d53188b',
'maniphest-task-edit-css' => '272daa84',
@@ -909,6 +909,9 @@
'javelin-uri',
'javelin-util',
),
+ '0392a5d8' => array(
+ 'javelin-install',
+ ),
'04023d82' => array(
'javelin-install',
'phuix-button-view',
@@ -993,6 +996,9 @@
'javelin-workflow',
'phuix-icon-view',
),
+ '111bfd2d' => array(
+ 'javelin-install',
+ ),
'1325b731' => array(
'javelin-behavior',
'javelin-uri',
@@ -1048,17 +1054,6 @@
'javelin-behavior',
'javelin-request',
),
- '2181739b' => array(
- 'javelin-install',
- 'javelin-dom',
- 'javelin-util',
- 'javelin-stratcom',
- 'javelin-workflow',
- 'phabricator-draggable-list',
- 'javelin-workboard-column',
- 'javelin-workboard-header-template',
- 'javelin-workboard-card-template',
- ),
'225bbb98' => array(
'javelin-install',
'javelin-reactor',
@@ -1110,6 +1105,15 @@
'javelin-json',
'phabricator-prefab',
),
+ '285c337a' => array(
+ 'javelin-behavior',
+ 'javelin-dom',
+ 'javelin-util',
+ 'javelin-vector',
+ 'javelin-stratcom',
+ 'javelin-workflow',
+ 'javelin-workboard-controller',
+ ),
'289bf236' => array(
'javelin-install',
'javelin-util',
@@ -1119,6 +1123,9 @@
'javelin-stratcom',
'javelin-behavior',
),
+ '2a61f8d4' => array(
+ 'javelin-install',
+ ),
'2a8b62d9' => array(
'multirow-row-manager',
'javelin-install',
@@ -1142,9 +1149,6 @@
'javelin-dom',
'phabricator-keyboard-shortcut',
),
- '2d641f7d' => array(
- 'javelin-install',
- ),
'2e255291' => array(
'javelin-install',
'javelin-util',
@@ -1343,6 +1347,11 @@
'javelin-dom',
'javelin-fx',
),
+ '533dd592' => array(
+ 'javelin-install',
+ 'javelin-workboard-card',
+ 'javelin-workboard-header',
+ ),
'534f1757' => array(
'phui-oi-list-view-css',
),
@@ -1427,11 +1436,6 @@
'60cd9241' => array(
'javelin-behavior',
),
- '6461f58b' => array(
- 'javelin-install',
- 'javelin-workboard-card',
- 'javelin-workboard-header',
- ),
'65bb0011' => array(
'javelin-behavior',
'javelin-dom',
@@ -1477,9 +1481,6 @@
'javelin-install',
'javelin-util',
),
- '6e75daea' => array(
- 'javelin-install',
- ),
70245195 => array(
'javelin-behavior',
'javelin-stratcom',
@@ -1839,9 +1840,6 @@
'javelin-behavior-device',
'javelin-vector',
),
- 'b0b5f90a' => array(
- 'javelin-install',
- ),
'b105a3a6' => array(
'javelin-behavior',
'javelin-stratcom',
@@ -1875,6 +1873,9 @@
'javelin-stratcom',
'javelin-dom',
),
+ 'b65351bd' => array(
+ 'javelin-install',
+ ),
'b7b73831' => array(
'javelin-behavior',
'javelin-dom',
@@ -1896,9 +1897,6 @@
'bc16cf33' => array(
'phui-workcard-view-css',
),
- 'bc92741f' => array(
- 'javelin-install',
- ),
'bdce4d78' => array(
'javelin-install',
'javelin-util',
@@ -1968,15 +1966,6 @@
'javelin-util',
'phabricator-keyboard-shortcut-manager',
),
- 'cca3f5f8' => array(
- 'javelin-behavior',
- 'javelin-dom',
- 'javelin-util',
- 'javelin-vector',
- 'javelin-stratcom',
- 'javelin-workflow',
- 'javelin-workboard-controller',
- ),
'cf32921f' => array(
'javelin-behavior',
'javelin-dom',
@@ -2134,6 +2123,17 @@
'phabricator-keyboard-shortcut',
'conpherence-thread-manager',
),
+ 'fc1664ff' => array(
+ 'javelin-install',
+ 'javelin-dom',
+ 'javelin-util',
+ 'javelin-stratcom',
+ 'javelin-workflow',
+ 'phabricator-draggable-list',
+ 'javelin-workboard-column',
+ 'javelin-workboard-header-template',
+ 'javelin-workboard-card-template',
+ ),
'fce5d170' => array(
'javelin-magical-init',
'javelin-util',
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
@@ -4052,10 +4052,14 @@
'PhabricatorProjectColumn' => 'applications/project/storage/PhabricatorProjectColumn.php',
'PhabricatorProjectColumnDetailController' => 'applications/project/controller/PhabricatorProjectColumnDetailController.php',
'PhabricatorProjectColumnEditController' => 'applications/project/controller/PhabricatorProjectColumnEditController.php',
+ 'PhabricatorProjectColumnHeader' => 'applications/project/order/PhabricatorProjectColumnHeader.php',
'PhabricatorProjectColumnHideController' => 'applications/project/controller/PhabricatorProjectColumnHideController.php',
+ 'PhabricatorProjectColumnNaturalOrder' => 'applications/project/order/PhabricatorProjectColumnNaturalOrder.php',
+ 'PhabricatorProjectColumnOrder' => 'applications/project/order/PhabricatorProjectColumnOrder.php',
'PhabricatorProjectColumnPHIDType' => 'applications/project/phid/PhabricatorProjectColumnPHIDType.php',
'PhabricatorProjectColumnPosition' => 'applications/project/storage/PhabricatorProjectColumnPosition.php',
'PhabricatorProjectColumnPositionQuery' => 'applications/project/query/PhabricatorProjectColumnPositionQuery.php',
+ 'PhabricatorProjectColumnPriorityOrder' => 'applications/project/order/PhabricatorProjectColumnPriorityOrder.php',
'PhabricatorProjectColumnQuery' => 'applications/project/query/PhabricatorProjectColumnQuery.php',
'PhabricatorProjectColumnSearchEngine' => 'applications/project/query/PhabricatorProjectColumnSearchEngine.php',
'PhabricatorProjectColumnTransaction' => 'applications/project/storage/PhabricatorProjectColumnTransaction.php',
@@ -10132,13 +10136,17 @@
),
'PhabricatorProjectColumnDetailController' => 'PhabricatorProjectBoardController',
'PhabricatorProjectColumnEditController' => 'PhabricatorProjectBoardController',
+ 'PhabricatorProjectColumnHeader' => 'Phobject',
'PhabricatorProjectColumnHideController' => 'PhabricatorProjectBoardController',
+ 'PhabricatorProjectColumnNaturalOrder' => 'PhabricatorProjectColumnOrder',
+ 'PhabricatorProjectColumnOrder' => 'Phobject',
'PhabricatorProjectColumnPHIDType' => 'PhabricatorPHIDType',
'PhabricatorProjectColumnPosition' => array(
'PhabricatorProjectDAO',
'PhabricatorPolicyInterface',
),
'PhabricatorProjectColumnPositionQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
+ 'PhabricatorProjectColumnPriorityOrder' => 'PhabricatorProjectColumnOrder',
'PhabricatorProjectColumnQuery' => 'PhabricatorCursorPagedPolicyAwareQuery',
'PhabricatorProjectColumnSearchEngine' => 'PhabricatorApplicationSearchEngine',
'PhabricatorProjectColumnTransaction' => 'PhabricatorApplicationTransaction',
diff --git a/src/applications/maniphest/storage/ManiphestTask.php b/src/applications/maniphest/storage/ManiphestTask.php
--- a/src/applications/maniphest/storage/ManiphestTask.php
+++ b/src/applications/maniphest/storage/ManiphestTask.php
@@ -248,14 +248,6 @@
return idx($this->properties, 'cover.thumbnailPHID');
}
- public function getWorkboardOrderVectors() {
- return array(
- PhabricatorProjectColumn::ORDER_PRIORITY => array(
- (int)-$this->getPriority(),
- ),
- );
- }
-
public function getPriorityKeyword() {
$priority = $this->getPriority();
@@ -267,14 +259,6 @@
return ManiphestTaskPriority::UNKNOWN_PRIORITY_KEYWORD;
}
- public function getWorkboardProperties() {
- return array(
- 'status' => $this->getStatus(),
- 'points' => (double)$this->getPoints(),
- 'priority' => $this->getPriority(),
- );
- }
-
/* -( PhabricatorSubscribableInterface )----------------------------------- */
diff --git a/src/applications/project/controller/PhabricatorProjectBoardViewController.php b/src/applications/project/controller/PhabricatorProjectBoardViewController.php
--- a/src/applications/project/controller/PhabricatorProjectBoardViewController.php
+++ b/src/applications/project/controller/PhabricatorProjectBoardViewController.php
@@ -614,49 +614,25 @@
$board->addPanel($panel);
}
- // It's possible for tasks to have an invalid/unknown priority in the
- // database. We still want to generate a header for these tasks so we
- // don't break the workboard.
- $priorities =
- ManiphestTaskPriority::getTaskPriorityMap() +
- mpull($all_tasks, null, 'getPriority');
- $priorities = array_keys($priorities);
-
- $headers = array();
- foreach ($priorities as $priority) {
- $header_key = sprintf('priority(%s)', $priority);
-
- $priority_name = ManiphestTaskPriority::getTaskPriorityName($priority);
- $priority_color = ManiphestTaskPriority::getTaskPriorityColor($priority);
- $priority_icon = ManiphestTaskPriority::getTaskPriorityIcon($priority);
-
- $icon_view = id(new PHUIIconView())
- ->setIcon("{$priority_icon} {$priority_color}");
-
- $template = phutil_tag(
- 'li',
- array(
- 'class' => 'workboard-group-header',
- ),
- array(
- $icon_view,
- $priority_name,
- ));
+ $order_key = $this->sortKey;
- $headers[] = array(
- 'order' => PhabricatorProjectColumn::ORDER_PRIORITY,
- 'key' => $header_key,
- 'template' => hsprintf('%s', $template),
- 'vector' => array(
- (int)-$priority,
- PhabricatorProjectColumn::NODETYPE_HEADER,
- ),
- 'editProperties' => array(
- PhabricatorProjectColumn::ORDER_PRIORITY => (int)$priority,
- ),
- );
+ $ordering_map = PhabricatorProjectColumnOrder::getAllOrders();
+ $ordering = id(clone $ordering_map[$order_key])
+ ->setViewer($viewer);
+
+ $headers = $ordering->getHeadersForObjects($all_tasks);
+ $headers = mpull($headers, 'toDictionary');
+
+ $vectors = $ordering->getSortVectorsForObjects($all_tasks);
+ $vector_map = array();
+ foreach ($vectors as $task_phid => $vector) {
+ $vector_map[$task_phid][$order_key] = $vector;
}
+ $header_keys = $ordering->getHeaderKeysForObjects($all_tasks);
+
+ $properties = array();
+
$behavior_config = array(
'moveURI' => $this->getApplicationURI('move/'.$project->getID().'/'),
'uploadURI' => '/file/dropupload/',
@@ -667,10 +643,11 @@
'boardPHID' => $project->getPHID(),
'order' => $this->sortKey,
'headers' => $headers,
+ 'headerKeys' => $header_keys,
'templateMap' => $templates,
'columnMaps' => $column_maps,
- 'orderMaps' => mpull($all_tasks, 'getWorkboardOrderVectors'),
- 'propertyMaps' => mpull($all_tasks, 'getWorkboardProperties'),
+ 'orderMaps' => $vector_map,
+ 'propertyMaps' => $properties,
'boardID' => $board_id,
'projectPHID' => $project->getPHID(),
@@ -680,7 +657,8 @@
$sort_menu = $this->buildSortMenu(
$viewer,
$project,
- $this->sortKey);
+ $this->sortKey,
+ $ordering_map);
$filter_menu = $this->buildFilterMenu(
$viewer,
@@ -775,7 +753,7 @@
return $default_sort;
}
- return PhabricatorProjectColumn::DEFAULT_ORDER;
+ return PhabricatorProjectColumnNaturalOrder::ORDERKEY;
}
private function getDefaultFilter(PhabricatorProject $project) {
@@ -789,41 +767,37 @@
}
private function isValidSort($sort) {
- switch ($sort) {
- case PhabricatorProjectColumn::ORDER_NATURAL:
- case PhabricatorProjectColumn::ORDER_PRIORITY:
- return true;
- }
-
- return false;
+ $map = PhabricatorProjectColumnOrder::getAllOrders();
+ return isset($map[$sort]);
}
private function buildSortMenu(
PhabricatorUser $viewer,
PhabricatorProject $project,
- $sort_key) {
-
- $sort_icon = id(new PHUIIconView())
- ->setIcon('fa-sort-amount-asc bluegrey');
-
- $named = array(
- PhabricatorProjectColumn::ORDER_NATURAL => pht('Natural'),
- PhabricatorProjectColumn::ORDER_PRIORITY => pht('Sort by Priority'),
- );
+ $sort_key,
+ array $ordering_map) {
$base_uri = $this->getURIWithState();
$items = array();
- foreach ($named as $key => $name) {
- $is_selected = ($key == $sort_key);
+ foreach ($ordering_map as $key => $ordering) {
+ // TODO: It would be desirable to build a real "PHUIIconView" here, but
+ // the pathway for threading that through all the view classes ends up
+ // being fairly complex, since some callers read the icon out of other
+ // views. For now, just stick with a string.
+ $ordering_icon = $ordering->getMenuIconIcon();
+ $ordering_name = $ordering->getDisplayName();
+
+ $is_selected = ($key === $sort_key);
if ($is_selected) {
- $active_order = $name;
+ $active_name = $ordering_name;
+ $active_icon = $ordering_icon;
}
$item = id(new PhabricatorActionView())
- ->setIcon('fa-sort-amount-asc')
+ ->setIcon($ordering_icon)
->setSelected($is_selected)
- ->setName($name);
+ ->setName($ordering_name);
$uri = $base_uri->alter('order', $key);
$item->setHref($uri);
@@ -856,8 +830,8 @@
}
$sort_button = id(new PHUIListItemView())
- ->setName($active_order)
- ->setIcon('fa-sort-amount-asc')
+ ->setName($active_name)
+ ->setIcon($active_icon)
->setHref('#')
->addSigil('boards-dropdown-menu')
->setMetadata(
diff --git a/src/applications/project/controller/PhabricatorProjectController.php b/src/applications/project/controller/PhabricatorProjectController.php
--- a/src/applications/project/controller/PhabricatorProjectController.php
+++ b/src/applications/project/controller/PhabricatorProjectController.php
@@ -149,7 +149,11 @@
return $this;
}
- protected function newCardResponse($board_phid, $object_phid) {
+ protected function newCardResponse(
+ $board_phid,
+ $object_phid,
+ PhabricatorProjectColumnOrder $ordering = null) {
+
$viewer = $this->getViewer();
$request = $this->getRequest();
@@ -158,12 +162,17 @@
$visible_phids = array();
}
- return id(new PhabricatorBoardResponseEngine())
+ $engine = id(new PhabricatorBoardResponseEngine())
->setViewer($viewer)
->setBoardPHID($board_phid)
->setObjectPHID($object_phid)
- ->setVisiblePHIDs($visible_phids)
- ->buildResponse();
+ ->setVisiblePHIDs($visible_phids);
+
+ if ($ordering) {
+ $engine->setOrdering($ordering);
+ }
+
+ return $engine->buildResponse();
}
public function renderHashtags(array $tags) {
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
@@ -13,7 +13,15 @@
$object_phid = $request->getStr('objectPHID');
$after_phid = $request->getStr('afterPHID');
$before_phid = $request->getStr('beforePHID');
- $order = $request->getStr('order', PhabricatorProjectColumn::DEFAULT_ORDER);
+
+ $order = $request->getStr('order');
+ if (!strlen($order)) {
+ $order = PhabricatorProjectColumnNaturalOrder::ORDERKEY;
+ }
+
+ $ordering = PhabricatorProjectColumnOrder::getOrderByKey($order);
+ $ordering = id(clone $ordering)
+ ->setViewer($viewer);
$edit_header = null;
$raw_header = $request->getStr('header');
@@ -88,9 +96,8 @@
) + $order_params,
));
- $header_xactions = $this->newHeaderTransactions(
+ $header_xactions = $ordering->getColumnTransactions(
$object,
- $order,
$edit_header);
foreach ($header_xactions as $header_xaction) {
$xactions[] = $header_xaction;
@@ -104,33 +111,7 @@
$editor->applyTransactions($object, $xactions);
- return $this->newCardResponse($board_phid, $object_phid);
- }
-
- private function newHeaderTransactions(
- ManiphestTask $task,
- $order,
- array $header) {
-
- $xactions = array();
-
- switch ($order) {
- case PhabricatorProjectColumn::ORDER_PRIORITY:
- $new_priority = idx($header, $order);
-
- if ($task->getPriority() !== $new_priority) {
- $keyword_map = ManiphestTaskPriority::getTaskPriorityKeywordsMap();
- $keyword = head(idx($keyword_map, $new_priority));
-
- $xactions[] = id(new ManiphestTransaction())
- ->setTransactionType(
- ManiphestTaskPriorityTransaction::TRANSACTIONTYPE)
- ->setNewValue($keyword);
- }
- break;
- }
-
- return $xactions;
+ return $this->newCardResponse($board_phid, $object_phid, $ordering);
}
}
diff --git a/src/applications/project/engine/PhabricatorBoardResponseEngine.php b/src/applications/project/engine/PhabricatorBoardResponseEngine.php
--- a/src/applications/project/engine/PhabricatorBoardResponseEngine.php
+++ b/src/applications/project/engine/PhabricatorBoardResponseEngine.php
@@ -6,6 +6,7 @@
private $boardPHID;
private $objectPHID;
private $visiblePHIDs;
+ private $ordering;
public function setViewer(PhabricatorUser $viewer) {
$this->viewer = $viewer;
@@ -43,10 +44,20 @@
return $this->visiblePHIDs;
}
+ public function setOrdering(PhabricatorProjectColumnOrder $ordering) {
+ $this->ordering = $ordering;
+ return $this;
+ }
+
+ public function getOrdering() {
+ return $this->ordering;
+ }
+
public function buildResponse() {
$viewer = $this->getViewer();
$object_phid = $this->getObjectPHID();
$board_phid = $this->getBoardPHID();
+ $ordering = $this->getOrdering();
// Load all the other tasks that are visible in the affected columns and
// perform layout for them.
@@ -74,10 +85,17 @@
->setViewer($viewer)
->withPHIDs($visible_phids)
->execute();
-
- $order_maps = array();
- foreach ($all_visible as $visible) {
- $order_maps[$visible->getPHID()] = $visible->getWorkboardOrderVectors();
+ $all_visible = mpull($all_visible, null, 'getPHID');
+
+ if ($ordering) {
+ $vectors = $ordering->getSortVectorsForObjects($all_visible);
+ $header_keys = $ordering->getHeaderKeysForObjects($all_visible);
+ $headers = $ordering->getHeadersForObjects($all_visible);
+ $headers = mpull($headers, 'toDictionary');
+ } else {
+ $vectors = array();
+ $header_keys = array();
+ $headers = array();
}
$object = id(new ManiphestTaskQuery())
@@ -91,14 +109,50 @@
$template = $this->buildTemplate($object);
+ $cards = array();
+ foreach ($all_visible as $card_phid => $object) {
+ $card = array(
+ 'vectors' => array(),
+ 'headers' => array(),
+ 'properties' => array(),
+ 'nodeHTMLTemplate' => null,
+ );
+
+ if ($ordering) {
+ $order_key = $ordering->getColumnOrderKey();
+
+ $vector = idx($vectors, $card_phid);
+ if ($vector !== null) {
+ $card['vectors'][$order_key] = $vector;
+ }
+
+ $header = idx($header_keys, $card_phid);
+ if ($header !== null) {
+ $card['headers'][$order_key] = $header;
+ }
+
+ $card['properties'] = array(
+ 'points' => (double)$object->getPoints(),
+ 'status' => $object->getStatus(),
+ );
+ }
+
+ if ($card_phid === $object_phid) {
+ $card['nodeHTMLTemplate'] = hsprintf('%s', $template);
+ }
+
+ $card['vectors'] = (object)$card['vectors'];
+ $card['headers'] = (object)$card['headers'];
+ $card['properties'] = (object)$card['properties'];
+
+ $cards[$card_phid] = $card;
+ }
+
$payload = array(
'objectPHID' => $object_phid,
- 'cardHTML' => $template,
'columnMaps' => $natural,
- 'orderMaps' => $order_maps,
- 'propertyMaps' => array(
- $object_phid => $object->getWorkboardProperties(),
- ),
+ 'cards' => $cards,
+ 'headers' => $headers,
);
return id(new AphrontAjaxResponse())
diff --git a/src/applications/project/order/PhabricatorProjectColumnHeader.php b/src/applications/project/order/PhabricatorProjectColumnHeader.php
new file mode 100644
--- /dev/null
+++ b/src/applications/project/order/PhabricatorProjectColumnHeader.php
@@ -0,0 +1,94 @@
+<?php
+
+final class PhabricatorProjectColumnHeader
+ extends Phobject {
+
+ private $orderKey;
+ private $headerKey;
+ private $sortVector;
+ private $name;
+ private $icon;
+ private $editProperties;
+
+ public function setOrderKey($order_key) {
+ $this->orderKey = $order_key;
+ return $this;
+ }
+
+ public function getOrderKey() {
+ return $this->orderKey;
+ }
+
+ public function setHeaderKey($header_key) {
+ $this->headerKey = $header_key;
+ return $this;
+ }
+
+ public function getHeaderKey() {
+ return $this->headerKey;
+ }
+
+ public function setSortVector(array $sort_vector) {
+ $this->sortVector = $sort_vector;
+ return $this;
+ }
+
+ public function getSortVector() {
+ return $this->sortVector;
+ }
+
+ public function setName($name) {
+ $this->name = $name;
+ return $this;
+ }
+
+ public function getName() {
+ return $this->name;
+ }
+
+ public function setIcon(PHUIIconView$icon) {
+ $this->icon = $icon;
+ return $this;
+ }
+
+ public function getIcon() {
+ return $this->icon;
+ }
+
+ public function setEditProperties(array $edit_properties) {
+ $this->editProperties = $edit_properties;
+ return $this;
+ }
+
+ public function getEditProperties() {
+ return $this->editProperties;
+ }
+
+ public function toDictionary() {
+ return array(
+ 'order' => $this->getOrderKey(),
+ 'key' => $this->getHeaderKey(),
+ 'template' => hsprintf('%s', $this->newView()),
+ 'vector' => $this->getSortVector(),
+ 'editProperties' => $this->getEditProperties(),
+ );
+ }
+
+ private function newView() {
+ $icon_view = $this->getIcon();
+ $name = $this->getName();
+
+ $template = phutil_tag(
+ 'li',
+ array(
+ 'class' => 'workboard-group-header',
+ ),
+ array(
+ $icon_view,
+ $name,
+ ));
+
+ return $template;
+ }
+
+}
diff --git a/src/applications/project/order/PhabricatorProjectColumnNaturalOrder.php b/src/applications/project/order/PhabricatorProjectColumnNaturalOrder.php
new file mode 100644
--- /dev/null
+++ b/src/applications/project/order/PhabricatorProjectColumnNaturalOrder.php
@@ -0,0 +1,12 @@
+<?php
+
+final class PhabricatorProjectColumnNaturalOrder
+ extends PhabricatorProjectColumnOrder {
+
+ const ORDERKEY = 'natural';
+
+ public function getDisplayName() {
+ return pht('Natural');
+ }
+
+}
diff --git a/src/applications/project/order/PhabricatorProjectColumnOrder.php b/src/applications/project/order/PhabricatorProjectColumnOrder.php
new file mode 100644
--- /dev/null
+++ b/src/applications/project/order/PhabricatorProjectColumnOrder.php
@@ -0,0 +1,176 @@
+<?php
+
+abstract class PhabricatorProjectColumnOrder
+ extends Phobject {
+
+ private $viewer;
+
+ final public function setViewer(PhabricatorUser $viewer) {
+ $this->viewer = $viewer;
+ return $this;
+ }
+
+ final public function getViewer() {
+ return $this->viewer;
+ }
+
+ final public function getColumnOrderKey() {
+ return $this->getPhobjectClassConstant('ORDERKEY');
+ }
+
+ final public static function getAllOrders() {
+ return id(new PhutilClassMapQuery())
+ ->setAncestorClass(__CLASS__)
+ ->setUniqueMethod('getColumnOrderKey')
+ ->execute();
+ }
+
+ final public static function getOrderByKey($key) {
+ $map = self::getAllOrders();
+
+ if (!isset($map[$key])) {
+ throw new Exception(
+ pht(
+ 'No column ordering exists with key "%s".',
+ $key));
+ }
+
+ return $map[$key];
+ }
+
+ final public function getColumnTransactions($object, array $header) {
+ $result = $this->newColumnTransactions($object, $header);
+
+ if (!is_array($result) && !is_null($result)) {
+ throw new Exception(
+ pht(
+ 'Expected "newColumnTransactions()" on "%s" to return "null" or a '.
+ 'list of transactions, but got "%s".',
+ get_class($this),
+ phutil_describe_type($result)));
+ }
+
+ if ($result === null) {
+ $result = array();
+ }
+
+ assert_instances_of($result, 'PhabricatorApplicationTransaction');
+
+ return $result;
+ }
+
+ final public function getMenuIconIcon() {
+ return $this->newMenuIconIcon();
+ }
+
+ protected function newMenuIconIcon() {
+ return 'fa-sort-amount-asc';
+ }
+
+ abstract public function getDisplayName();
+
+ protected function newColumnTransactions($object, array $header) {
+ return array();
+ }
+
+ final public function getHeadersForObjects(array $objects) {
+ $headers = $this->newHeadersForObjects($objects);
+
+ if (!is_array($headers)) {
+ throw new Exception(
+ pht(
+ 'Expected "newHeadersForObjects()" on "%s" to return a list '.
+ 'of headers, but got "%s".',
+ get_class($this),
+ phutil_describe_type($headers)));
+ }
+
+ assert_instances_of($headers, 'PhabricatorProjectColumnHeader');
+
+ // Add a "0" to the end of each header. This makes them sort above object
+ // cards in the same group.
+ foreach ($headers as $header) {
+ $vector = $header->getSortVector();
+ $vector[] = 0;
+ $header->setSortVector($vector);
+ }
+
+ return $headers;
+ }
+
+ protected function newHeadersForObjects(array $objects) {
+ return array();
+ }
+
+ final public function getSortVectorsForObjects(array $objects) {
+ $vectors = $this->newSortVectorsForObjects($objects);
+
+ if (!is_array($vectors)) {
+ throw new Exception(
+ pht(
+ 'Expected "newSortVectorsForObjects()" on "%s" to return a '.
+ 'map of vectors, but got "%s".',
+ get_class($this),
+ phutil_describe_type($vectors)));
+ }
+
+ assert_same_keys($objects, $vectors);
+
+ return $vectors;
+ }
+
+ protected function newSortVectorsForObjects(array $objects) {
+ $vectors = array();
+
+ foreach ($objects as $key => $object) {
+ $vectors[$key] = $this->newSortVectorForObject($object);
+ }
+
+ return $vectors;
+ }
+
+ protected function newSortVectorForObject($object) {
+ return array();
+ }
+
+ final public function getHeaderKeysForObjects(array $objects) {
+ $header_keys = $this->newHeaderKeysForObjects($objects);
+
+ if (!is_array($header_keys)) {
+ throw new Exception(
+ pht(
+ 'Expected "newHeaderKeysForObject()" on "%s" to return a '.
+ 'map of header keys, but got "%s".',
+ get_class($this),
+ phutil_describe_type($header_keys)));
+ }
+
+ assert_same_keys($objects, $header_keys);
+
+ return $header_keys;
+ }
+
+ protected function newHeaderKeysForObjects(array $objects) {
+ $header_keys = array();
+
+ foreach ($objects as $key => $object) {
+ $header_keys[$key] = $this->newHeaderKeyForObject($object);
+ }
+
+ return $header_keys;
+ }
+
+ protected function newHeaderKeyForObject($object) {
+ return null;
+ }
+
+ final protected function newTransaction($object) {
+ return $object->getApplicationTransactionTemplate();
+ }
+
+ final protected function newHeader() {
+ return id(new PhabricatorProjectColumnHeader())
+ ->setOrderKey($this->getColumnOrderKey());
+ }
+
+}
diff --git a/src/applications/project/order/PhabricatorProjectColumnPriorityOrder.php b/src/applications/project/order/PhabricatorProjectColumnPriorityOrder.php
new file mode 100644
--- /dev/null
+++ b/src/applications/project/order/PhabricatorProjectColumnPriorityOrder.php
@@ -0,0 +1,91 @@
+<?php
+
+final class PhabricatorProjectColumnPriorityOrder
+ extends PhabricatorProjectColumnOrder {
+
+ const ORDERKEY = 'priority';
+
+ public function getDisplayName() {
+ return pht('Group by Priority');
+ }
+
+ protected function newMenuIconIcon() {
+ return 'fa-sort-numeric-asc';
+ }
+
+ protected function newHeaderKeyForObject($object) {
+ return $this->newHeaderKeyForPriority($object->getPriority());
+ }
+
+ private function newHeaderKeyForPriority($priority) {
+ return sprintf('priority(%d)', $priority);
+ }
+
+ protected function newSortVectorForObject($object) {
+ return $this->newSortVectorForPriority($object->getPriority());
+ }
+
+ private function newSortVectorForPriority($priority) {
+ return array(
+ (int)-$priority,
+ );
+ }
+
+ protected function newHeadersForObjects(array $objects) {
+ $priorities = ManiphestTaskPriority::getTaskPriorityMap();
+
+ // It's possible for tasks to have an invalid/unknown priority in the
+ // database. We still want to generate a header for these tasks so we
+ // don't break the workboard.
+ $priorities = $priorities + mpull($objects, null, 'getPriority');
+
+ $priorities = array_keys($priorities);
+
+ $headers = array();
+ foreach ($priorities as $priority) {
+ $header_key = $this->newHeaderKeyForPriority($priority);
+ $sort_vector = $this->newSortVectorForPriority($priority);
+
+ $priority_name = ManiphestTaskPriority::getTaskPriorityName($priority);
+ $priority_color = ManiphestTaskPriority::getTaskPriorityColor($priority);
+ $priority_icon = ManiphestTaskPriority::getTaskPriorityIcon($priority);
+
+ $icon_view = id(new PHUIIconView())
+ ->setIcon($priority_icon, $priority_color);
+
+ $header = $this->newHeader()
+ ->setHeaderKey($header_key)
+ ->setSortVector($sort_vector)
+ ->setName($priority_name)
+ ->setIcon($icon_view)
+ ->setEditProperties(
+ array(
+ 'value' => (int)$priority,
+ ));
+
+ $headers[] = $header;
+ }
+
+ return $headers;
+ }
+
+ protected function newColumnTransactions($object, array $header) {
+ $new_priority = idx($header, 'value');
+
+ if ($object->getPriority() === $new_priority) {
+ return null;
+ }
+
+ $keyword_map = ManiphestTaskPriority::getTaskPriorityKeywordsMap();
+ $keyword = head(idx($keyword_map, $new_priority));
+
+ $xactions = array();
+ $xactions[] = $this->newTransaction($object)
+ ->setTransactionType(ManiphestTaskPriorityTransaction::TRANSACTIONTYPE)
+ ->setNewValue($keyword);
+
+ return $xactions;
+ }
+
+
+}
diff --git a/src/applications/project/storage/PhabricatorProjectColumn.php b/src/applications/project/storage/PhabricatorProjectColumn.php
--- a/src/applications/project/storage/PhabricatorProjectColumn.php
+++ b/src/applications/project/storage/PhabricatorProjectColumn.php
@@ -12,13 +12,6 @@
const STATUS_ACTIVE = 0;
const STATUS_HIDDEN = 1;
- const DEFAULT_ORDER = 'natural';
- const ORDER_NATURAL = 'natural';
- const ORDER_PRIORITY = 'priority';
-
- const NODETYPE_HEADER = 0;
- const NODETYPE_CARD = 1;
-
protected $name;
protected $status;
protected $projectPHID;
diff --git a/webroot/rsrc/js/application/projects/WorkboardBoard.js b/webroot/rsrc/js/application/projects/WorkboardBoard.js
--- a/webroot/rsrc/js/application/projects/WorkboardBoard.js
+++ b/webroot/rsrc/js/application/projects/WorkboardBoard.js
@@ -289,7 +289,6 @@
var columns = this.getColumns();
var phid = response.objectPHID;
- var card = this.getCardTemplate(phid);
for (var add_phid in response.columnMaps) {
var target_column = this.getColumn(add_phid);
@@ -302,18 +301,6 @@
target_column.newCard(phid);
}
- card.setNodeHTMLTemplate(response.cardHTML);
-
- var order_maps = response.orderMaps;
- for (var order_phid in order_maps) {
- var card_template = this.getCardTemplate(order_phid);
- for (var order_key in order_maps[order_phid]) {
- card_template.setSortVector(
- order_key,
- order_maps[order_phid][order_key]);
- }
- }
-
var column_maps = response.columnMaps;
var natural_column;
for (var natural_phid in column_maps) {
@@ -329,10 +316,37 @@
natural_column.setNaturalOrder(column_maps[natural_phid]);
}
- var property_maps = response.propertyMaps;
- for (var property_phid in property_maps) {
- this.getCardTemplate(property_phid)
- .setObjectProperties(property_maps[property_phid]);
+ for (var card_phid in response.cards) {
+ var card_data = response.cards[card_phid];
+ var card_template = this.getCardTemplate(card_phid);
+
+ if (card_data.nodeHTMLTemplate) {
+ card_template.setNodeHTMLTemplate(card_data.nodeHTMLTemplate);
+ }
+
+ var order;
+ for (order in card_data.vectors) {
+ card_template.setSortVector(order, card_data.vectors[order]);
+ }
+
+ for (order in card_data.headers) {
+ card_template.setHeaderKey(order, card_data.headers[order]);
+ }
+
+ for (var key in card_data.properties) {
+ card_template.setObjectProperty(key, card_data.properties[key]);
+ }
+ }
+
+ var headers = response.headers;
+ for (var jj = 0; jj < headers.length; jj++) {
+ var header = headers[jj];
+
+ this.getHeaderTemplate(header.key)
+ .setOrder(header.order)
+ .setNodeHTMLTemplate(header.template)
+ .setVector(header.vector)
+ .setEditProperties(header.editProperties);
}
for (var column_phid in columns) {
diff --git a/webroot/rsrc/js/application/projects/WorkboardCard.js b/webroot/rsrc/js/application/projects/WorkboardCard.js
--- a/webroot/rsrc/js/application/projects/WorkboardCard.js
+++ b/webroot/rsrc/js/application/projects/WorkboardCard.js
@@ -29,7 +29,8 @@
},
getProperties: function() {
- return this.getColumn().getBoard().getCardTemplate(this.getPHID())
+ return this.getColumn().getBoard()
+ .getCardTemplate(this.getPHID())
.getObjectProperties();
},
@@ -41,10 +42,6 @@
return this.getProperties().status;
},
- getPriority: function(order) {
- return this.getProperties().priority;
- },
-
getNode: function() {
if (!this._root) {
var phid = this.getPHID();
diff --git a/webroot/rsrc/js/application/projects/WorkboardCardTemplate.js b/webroot/rsrc/js/application/projects/WorkboardCardTemplate.js
--- a/webroot/rsrc/js/application/projects/WorkboardCardTemplate.js
+++ b/webroot/rsrc/js/application/projects/WorkboardCardTemplate.js
@@ -9,6 +9,7 @@
construct: function(phid) {
this._phid = phid;
this._vectors = {};
+ this._headerKeys = {};
this.setObjectProperties({});
},
@@ -19,7 +20,9 @@
members: {
_phid: null,
+ _html: null,
_vectors: null,
+ _headerKeys: null,
getPHID: function() {
return this._phid;
@@ -39,8 +42,22 @@
return this._vectors[order];
},
+ setHeaderKey: function(order, key) {
+ this._headerKeys[order] = key;
+ return this;
+ },
+
+ getHeaderKey: function(order) {
+ return this._headerKeys[order];
+ },
+
newNode: function() {
return JX.$H(this._html).getFragment().firstChild;
+ },
+
+ setObjectProperty: function(key, value) {
+ this.getObjectProperties()[key] = value;
+ return this;
}
}
diff --git a/webroot/rsrc/js/application/projects/WorkboardColumn.js b/webroot/rsrc/js/application/projects/WorkboardColumn.js
--- a/webroot/rsrc/js/application/projects/WorkboardColumn.js
+++ b/webroot/rsrc/js/application/projects/WorkboardColumn.js
@@ -189,6 +189,9 @@
var board = this.getBoard();
var order = board.getOrder();
+ // TODO: This should be modularized into "ProjectColumnOrder" classes,
+ // but is currently hard-coded.
+
switch (order) {
case 'natural':
return false;
@@ -197,15 +200,6 @@
return true;
},
- _getCardHeaderKey: function(card, order) {
- switch (order) {
- case 'priority':
- return 'priority(' + card.getPriority() + ')';
- default:
- return null;
- }
- },
-
redraw: function() {
var board = this.getBoard();
var order = board.getOrder();
@@ -235,7 +229,9 @@
// cards in a column.
if (has_headers) {
- var header_key = this._getCardHeaderKey(card, order);
+ var header_key = board.getCardTemplate(card.getPHID())
+ .getHeaderKey(order);
+
if (!seen_headers[header_key]) {
while (header_keys.length) {
var next = header_keys.pop();
diff --git a/webroot/rsrc/js/application/projects/WorkboardHeader.js b/webroot/rsrc/js/application/projects/WorkboardHeader.js
--- a/webroot/rsrc/js/application/projects/WorkboardHeader.js
+++ b/webroot/rsrc/js/application/projects/WorkboardHeader.js
@@ -27,12 +27,16 @@
getNode: function() {
if (!this._root) {
var header_key = this.getHeaderKey();
- var board = this.getColumn().getBoard();
- var template = board.getHeaderTemplate(header_key).getTemplate();
- this._root = JX.$H(template).getFragment().firstChild;
- JX.Stratcom.getData(this._root).headerKey = header_key;
+ var root = this.getColumn().getBoard()
+ .getHeaderTemplate(header_key)
+ .newNode();
+
+ JX.Stratcom.getData(root).headerKey = header_key;
+
+ this._root = root;
}
+
return this._root;
},
diff --git a/webroot/rsrc/js/application/projects/WorkboardHeaderTemplate.js b/webroot/rsrc/js/application/projects/WorkboardHeaderTemplate.js
--- a/webroot/rsrc/js/application/projects/WorkboardHeaderTemplate.js
+++ b/webroot/rsrc/js/application/projects/WorkboardHeaderTemplate.js
@@ -19,9 +19,19 @@
members: {
_headerKey: null,
+ _html: null,
getHeaderKey: function() {
return this._headerKey;
+ },
+
+ setNodeHTMLTemplate: function(html) {
+ this._html = html;
+ return this;
+ },
+
+ newNode: function() {
+ return JX.$H(this._html).getFragment().firstChild;
}
}
diff --git a/webroot/rsrc/js/application/projects/behavior-project-boards.js b/webroot/rsrc/js/application/projects/behavior-project-boards.js
--- a/webroot/rsrc/js/application/projects/behavior-project-boards.js
+++ b/webroot/rsrc/js/application/projects/behavior-project-boards.js
@@ -116,11 +116,17 @@
board.getHeaderTemplate(header.key)
.setOrder(header.order)
- .setTemplate(header.template)
+ .setNodeHTMLTemplate(header.template)
.setVector(header.vector)
.setEditProperties(header.editProperties);
}
+ var header_keys = config.headerKeys;
+ for (var header_phid in header_keys) {
+ board.getCardTemplate(header_phid)
+ .setHeaderKey(config.order, header_keys[header_phid]);
+ }
+
board.start();
});
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Thu, Apr 3, 4:22 PM (3 w, 2 d ago)
Storage Engine
amazon-s3
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
phabricator/secure/t6/nr/e42jfcv5dlpkaf5o
Default Alt Text
D20269.diff (41 KB)
Attached To
Mode
D20269: Modularize workboard column orders
Attached
Detach File
Event Timeline
Log In to Comment