Page Menu
Home
Phabricator
Search
Configure Global Search
Log In
Files
F14834823
D20247.id.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Flag For Later
Size
19 KB
Referenced Files
None
Subscribers
None
D20247.id.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
@@ -178,7 +178,7 @@
'rsrc/css/phui/workboards/phui-workboard-color.css' => 'e86de308',
'rsrc/css/phui/workboards/phui-workboard.css' => '74fc9d98',
'rsrc/css/phui/workboards/phui-workcard.css' => '8c536f90',
- 'rsrc/css/phui/workboards/phui-workpanel.css' => '7e12d43c',
+ 'rsrc/css/phui/workboards/phui-workpanel.css' => 'bc16cf33',
'rsrc/css/sprite-login.css' => '18b368a6',
'rsrc/css/sprite-tokens.css' => 'f1896dc5',
'rsrc/css/syntax/syntax-default.css' => '055fc231',
@@ -409,11 +409,13 @@
'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' => 'fd96a6e8',
- 'rsrc/js/application/projects/WorkboardCard.js' => '9a513421',
- 'rsrc/js/application/projects/WorkboardColumn.js' => '1f71e559',
+ 'rsrc/js/application/projects/WorkboardBoard.js' => 'e4e2d107',
+ 'rsrc/js/application/projects/WorkboardCard.js' => 'c23ddfde',
+ 'rsrc/js/application/projects/WorkboardColumn.js' => 'fd9cb972',
'rsrc/js/application/projects/WorkboardController.js' => '42c7a5a7',
- 'rsrc/js/application/projects/behavior-project-boards.js' => '05c74d65',
+ 'rsrc/js/application/projects/WorkboardHeader.js' => '354c5c0e',
+ 'rsrc/js/application/projects/WorkboardHeaderTemplate.js' => '9b86cd0d',
+ 'rsrc/js/application/projects/behavior-project-boards.js' => 'a3f6b67f',
'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',
@@ -655,7 +657,7 @@
'javelin-behavior-phuix-example' => 'c2c500a7',
'javelin-behavior-policy-control' => '0eaa33a9',
'javelin-behavior-policy-rule-editor' => '9347f172',
- 'javelin-behavior-project-boards' => '05c74d65',
+ 'javelin-behavior-project-boards' => 'a3f6b67f',
'javelin-behavior-project-create' => '34c53422',
'javelin-behavior-quicksand-blacklist' => '5a6f6a06',
'javelin-behavior-read-only-warning' => 'b9109f8f',
@@ -727,10 +729,12 @@
'javelin-view-renderer' => '9aae2b66',
'javelin-view-visitor' => '308f9fe4',
'javelin-websocket' => 'fdc13e4e',
- 'javelin-workboard-board' => 'fd96a6e8',
- 'javelin-workboard-card' => '9a513421',
- 'javelin-workboard-column' => '1f71e559',
+ 'javelin-workboard-board' => 'e4e2d107',
+ 'javelin-workboard-card' => 'c23ddfde',
+ 'javelin-workboard-column' => 'fd9cb972',
'javelin-workboard-controller' => '42c7a5a7',
+ 'javelin-workboard-header' => '354c5c0e',
+ 'javelin-workboard-header-template' => '9b86cd0d',
'javelin-workflow' => '958e9045',
'maniphest-report-css' => '3d53188b',
'maniphest-task-edit-css' => '272daa84',
@@ -854,7 +858,7 @@
'phui-workboard-color-css' => 'e86de308',
'phui-workboard-view-css' => '74fc9d98',
'phui-workcard-view-css' => '8c536f90',
- 'phui-workpanel-view-css' => '7e12d43c',
+ 'phui-workpanel-view-css' => 'bc16cf33',
'phuix-action-list-view' => 'c68f183f',
'phuix-action-view' => 'aaa08f3b',
'phuix-autocomplete' => '8f139ef0',
@@ -915,15 +919,6 @@
'javelin-dom',
'javelin-workflow',
),
- '05c74d65' => array(
- 'javelin-behavior',
- 'javelin-dom',
- 'javelin-util',
- 'javelin-vector',
- 'javelin-stratcom',
- 'javelin-workflow',
- 'javelin-workboard-controller',
- ),
'05d290ef' => array(
'javelin-install',
'javelin-util',
@@ -1034,10 +1029,6 @@
'javelin-behavior',
'javelin-dom',
),
- '1f71e559' => array(
- 'javelin-install',
- 'javelin-workboard-card',
- ),
'1ff278aa' => array(
'phui-button-css',
),
@@ -1172,6 +1163,9 @@
'javelin-stratcom',
'javelin-workflow',
),
+ '354c5c0e' => array(
+ 'javelin-install',
+ ),
'37b8a04a' => array(
'javelin-install',
'javelin-util',
@@ -1535,9 +1529,6 @@
'javelin-install',
'javelin-dom',
),
- '7e12d43c' => array(
- 'phui-workcard-view-css',
- ),
'80bff3af' => array(
'javelin-install',
'javelin-typeahead-source',
@@ -1701,9 +1692,6 @@
'javelin-dom',
'javelin-router',
),
- '9a513421' => array(
- 'javelin-install',
- ),
'9aae2b66' => array(
'javelin-install',
'javelin-util',
@@ -1713,6 +1701,9 @@
'javelin-dom',
'javelin-stratcom',
),
+ '9b86cd0d' => array(
+ 'javelin-install',
+ ),
'9cec214e' => array(
'javelin-behavior',
'javelin-stratcom',
@@ -1737,6 +1728,15 @@
'a241536a' => array(
'javelin-install',
),
+ 'a3f6b67f' => array(
+ 'javelin-behavior',
+ 'javelin-dom',
+ 'javelin-util',
+ 'javelin-vector',
+ 'javelin-stratcom',
+ 'javelin-workflow',
+ 'javelin-workboard-controller',
+ ),
'a4356cde' => array(
'javelin-install',
'javelin-dom',
@@ -1887,6 +1887,9 @@
'javelin-uri',
'phabricator-notification',
),
+ 'bc16cf33' => array(
+ 'phui-workcard-view-css',
+ ),
'bdce4d78' => array(
'javelin-install',
'javelin-util',
@@ -1903,6 +1906,9 @@
'javelin-stratcom',
'javelin-uri',
),
+ 'c23ddfde' => array(
+ 'javelin-install',
+ ),
'c2c500a7' => array(
'javelin-install',
'javelin-dom',
@@ -2019,6 +2025,16 @@
'javelin-dom',
'javelin-history',
),
+ 'e4e2d107' => array(
+ 'javelin-install',
+ 'javelin-dom',
+ 'javelin-util',
+ 'javelin-stratcom',
+ 'javelin-workflow',
+ 'phabricator-draggable-list',
+ 'javelin-workboard-column',
+ 'javelin-workboard-header-template',
+ ),
'e562708c' => array(
'javelin-install',
),
@@ -2120,14 +2136,10 @@
'javelin-magical-init',
'javelin-util',
),
- 'fd96a6e8' => array(
+ 'fd9cb972' => array(
'javelin-install',
- 'javelin-dom',
- 'javelin-util',
- 'javelin-stratcom',
- 'javelin-workflow',
- 'phabricator-draggable-list',
- 'javelin-workboard-column',
+ 'javelin-workboard-card',
+ 'javelin-workboard-header',
),
'fdc13e4e' => array(
'javelin-install',
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
@@ -306,6 +306,7 @@
return array(
'status' => $this->getStatus(),
'points' => (double)$this->getPoints(),
+ 'priority' => $this->getPriority(),
);
}
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
@@ -621,6 +621,45 @@
$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,
+ ));
+
+ $headers[] = array(
+ 'order' => 'priority',
+ 'key' => $header_key,
+ 'template' => hsprintf('%s', $template),
+ 'vector' => array(
+ (int)-$priority,
+ ),
+ );
+ }
+
$behavior_config = array(
'moveURI' => $this->getApplicationURI('move/'.$project->getID().'/'),
'uploadURI' => '/file/dropupload/',
@@ -630,6 +669,7 @@
'boardPHID' => $project->getPHID(),
'order' => $this->sortKey,
+ 'headers' => $headers,
'templateMap' => $templates,
'columnMaps' => $column_maps,
'orderMaps' => mpull($all_tasks, 'getWorkboardOrderVectors'),
diff --git a/webroot/rsrc/css/phui/workboards/phui-workpanel.css b/webroot/rsrc/css/phui/workboards/phui-workpanel.css
--- a/webroot/rsrc/css/phui/workboards/phui-workpanel.css
+++ b/webroot/rsrc/css/phui/workboards/phui-workpanel.css
@@ -145,3 +145,16 @@
.phui-workpanel-view.workboard-column-drop-target .phui-box-grey {
border-color: {$lightblueborder};
}
+
+.workboard-group-header {
+ background: rgba({$alphablue}, 0.10);
+ padding: 4px 8px;
+ margin: 0 0 8px -8px;
+ border-bottom: 1px solid {$lightgreyborder};
+ font-weight: bold;
+ color: {$darkgreytext};
+}
+
+.workboard-group-header .phui-icon-view {
+ margin-right: 8px;
+}
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
@@ -7,6 +7,7 @@
* javelin-workflow
* phabricator-draggable-list
* javelin-workboard-column
+ * javelin-workboard-header-template
* @javelin
*/
@@ -20,6 +21,7 @@
this._templates = {};
this._orderMaps = {};
this._propertiesMap = {};
+ this._headers = {};
this._buildColumns();
},
@@ -36,6 +38,7 @@
_templates: null,
_orderMaps: null,
_propertiesMap: null,
+ _headers: null,
getRoot: function() {
return this._root;
@@ -58,6 +61,36 @@
return this;
},
+ getHeaderTemplate: function(header_key) {
+ if (!this._headers[header_key]) {
+ this._headers[header_key] = new JX.WorkboardHeaderTemplate(header_key);
+ }
+
+ return this._headers[header_key];
+ },
+
+ getHeaderTemplatesForOrder: function(order) {
+ var templates = [];
+
+ for (var k in this._headers) {
+ var header = this._headers[k];
+
+ if (header.getOrder() !== order) {
+ continue;
+ }
+
+ templates.push(header);
+ }
+
+ templates.sort(JX.bind(this, this._sortHeaderTemplates));
+
+ return templates;
+ },
+
+ _sortHeaderTemplates: function(u, v) {
+ return this.compareVectors(u.getVector(), v.getVector());
+ },
+
setObjectProperties: function(phid, properties) {
this._propertiesMap[phid] = properties;
return this;
@@ -84,6 +117,20 @@
return this._orderMaps[phid][key];
},
+ compareVectors: function(u_vec, v_vec) {
+ for (var ii = 0; ii < u_vec.length; ii++) {
+ if (u_vec[ii] > v_vec[ii]) {
+ return 1;
+ }
+
+ if (u_vec[ii] < v_vec[ii]) {
+ return -1;
+ }
+ }
+
+ return 0;
+ },
+
start: function() {
this._setupDragHandlers();
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
@@ -40,6 +40,10 @@
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/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
@@ -2,6 +2,7 @@
* @provides javelin-workboard-column
* @requires javelin-install
* javelin-workboard-card
+ * javelin-workboard-header
* @javelin
*/
@@ -21,6 +22,8 @@
'column-points-content');
this._cards = {};
+ this._headers = {};
+ this._objects = [];
this._naturalOrder = [];
},
@@ -29,11 +32,13 @@
_root: null,
_board: null,
_cards: null,
+ _headers: null,
_naturalOrder: null,
_panel: null,
_pointsNode: null,
_pointsContentNode: null,
_dirty: true,
+ _objects: null,
getPHID: function() {
return this._phid;
@@ -148,24 +153,85 @@
return this._dirty;
},
+ getHeader: function(key) {
+ if (!this._headers[key]) {
+ this._headers[key] = new JX.WorkboardHeader(this, key);
+ }
+ return this._headers[key];
+ },
+
+ _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();
var list;
+ var has_headers;
if (order == 'natural') {
list = this._getCardsSortedNaturally();
+ has_headers = false;
} else {
list = this._getCardsSortedByKey(order);
+ has_headers = true;
}
- var content = [];
- for (var ii = 0; ii < list.length; ii++) {
+ var ii;
+ var objects = [];
+
+ var header_keys = [];
+ var seen_headers = {};
+ if (has_headers) {
+ var header_templates = board.getHeaderTemplatesForOrder(order);
+ for (var k in header_templates) {
+ header_keys.push(header_templates[k].getHeaderKey());
+ }
+ header_keys.reverse();
+ }
+
+ for (ii = 0; ii < list.length; ii++) {
var card = list[ii];
- var node = card.getNode();
- content.push(node);
+ // If a column has a "High" priority card and a "Low" priority card,
+ // we need to add the "Normal" header in between them. This allows
+ // you to change priority to "Normal" even if there are no "Normal"
+ // cards in a column.
+
+ if (has_headers) {
+ var header_key = this._getCardHeaderKey(card, order);
+ if (!seen_headers[header_key]) {
+ while (header_keys.length) {
+ var next = header_keys.pop();
+
+ var header = this.getHeader(next);
+ objects.push(header);
+ seen_headers[header_key] = true;
+
+ if (next === header_key) {
+ break;
+ }
+ }
+ }
+ }
+ objects.push(card);
+ }
+
+ this._objects = objects;
+
+ var content = [];
+ for (ii = 0; ii < this._objects.length; ii++) {
+ var object = this._objects[ii];
+
+ var node = object.getNode();
+ content.push(node);
}
JX.DOM.setContent(this.getRoot(), content);
@@ -182,10 +248,10 @@
var src_phid = JX.Stratcom.getData(src_node).objectPHID;
var dst_phid = JX.Stratcom.getData(dst_node).objectPHID;
- var u_vec = this.getBoard().getOrderVector(src_phid, order);
- var v_vec = this.getBoard().getOrderVector(dst_phid, order);
+ var u_vec = board.getOrderVector(src_phid, order);
+ var v_vec = board.getOrderVector(dst_phid, order);
- return this._compareVectors(u_vec, v_vec);
+ return board.compareVectors(u_vec, v_vec);
},
setIsDropTarget: function(is_target) {
@@ -218,24 +284,11 @@
},
_sortCards: function(order, u, v) {
- var u_vec = this.getBoard().getOrderVector(u.getPHID(), order);
- var v_vec = this.getBoard().getOrderVector(v.getPHID(), order);
-
- return this._compareVectors(u_vec, v_vec);
- },
-
- _compareVectors: function(u_vec, v_vec) {
- for (var ii = 0; ii < u_vec.length; ii++) {
- if (u_vec[ii] > v_vec[ii]) {
- return 1;
- }
-
- if (u_vec[ii] < v_vec[ii]) {
- return -1;
- }
- }
+ var board = this.getBoard();
+ var u_vec = board.getOrderVector(u.getPHID(), order);
+ var v_vec = board.getOrderVector(v.getPHID(), order);
- return 0;
+ return board.compareVectors(u_vec, v_vec);
},
_redrawFrame: function() {
diff --git a/webroot/rsrc/js/application/projects/WorkboardHeader.js b/webroot/rsrc/js/application/projects/WorkboardHeader.js
new file mode 100644
--- /dev/null
+++ b/webroot/rsrc/js/application/projects/WorkboardHeader.js
@@ -0,0 +1,38 @@
+/**
+ * @provides javelin-workboard-header
+ * @requires javelin-install
+ * @javelin
+ */
+
+JX.install('WorkboardHeader', {
+
+ construct: function(column, header_key) {
+ this._column = column;
+ this._headerKey = header_key;
+ },
+
+ members: {
+ _root: null,
+ _column: null,
+ _headerKey: null,
+
+ getColumn: function() {
+ return this._column;
+ },
+
+ getHeaderKey: function() {
+ return this._headerKey;
+ },
+
+ 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;
+ }
+ return this._root;
+ }
+ }
+
+});
diff --git a/webroot/rsrc/js/application/projects/WorkboardHeaderTemplate.js b/webroot/rsrc/js/application/projects/WorkboardHeaderTemplate.js
new file mode 100644
--- /dev/null
+++ b/webroot/rsrc/js/application/projects/WorkboardHeaderTemplate.js
@@ -0,0 +1,28 @@
+/**
+ * @provides javelin-workboard-header-template
+ * @requires javelin-install
+ * @javelin
+ */
+
+JX.install('WorkboardHeaderTemplate', {
+
+ construct: function(header_key) {
+ this._headerKey = header_key;
+ },
+
+ properties: {
+ template: null,
+ order: null,
+ vector: null
+ },
+
+ members: {
+ _headerKey: null,
+
+ getHeaderKey: function() {
+ return this._headerKey;
+ }
+
+ }
+
+});
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
@@ -105,6 +105,16 @@
board.setObjectProperties(property_phid, property_maps[property_phid]);
}
+ var headers = config.headers;
+ for (var jj = 0; jj < headers.length; jj++) {
+ var header = headers[jj];
+
+ board.getHeaderTemplate(header.key)
+ .setOrder(header.order)
+ .setTemplate(header.template)
+ .setVector(header.vector);
+ }
+
board.start();
});
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Jan 31, 5:26 PM (4 h, 41 m)
Storage Engine
blob
Storage Format
Encrypted (AES-256-CBC)
Storage Handle
7079251
Default Alt Text
D20247.id.diff (19 KB)
Attached To
Mode
D20247: Add priority group headers to workboard columns (display only)
Attached
Detach File
Event Timeline
Log In to Comment