@recaptime-dev's working patches + fork for Phorge, a community fork of Phabricator. (Upstream dev and stable branches are at upstream/main and upstream/stable respectively.) hq.recaptime.dev/wiki/Phorge
phorge phabricator
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Make pressing "R" on your keyboard reload the card state on workboards

Summary:
Depends on D20638. Ref T4900. This is an incremental step toward proper workboard updates.

Currently, the client can mostly update its view because we do updates when you edit or move a card, and the client and server know how to send lists of card updates, so a lot of the work is already done.

However, the code assumes we're only updating/redrawing one card at a time. Make the client accept and process multiple card updates.

In future changes, I'll add versioning (so we only update cards that have actually changed), fix the "TODO" around ordering, and move toward actual Aphlict-based real-time updates.

Test Plan:
- Opened the same workboard in two windows.
- Edited cards in one window, pressed "R" (capital letter, with no modifier keys) to reload the second window.
- Saw edits and moves reflected accurately after sync, except for some special cases of header/order interaction (see "TODO").

Reviewers: amckinley

Reviewed By: amckinley

Maniphest Tasks: T4900

Differential Revision: https://secure.phabricator.com/D20639

+283 -129
+38 -38
resources/celerity/map.php
··· 412 412 'rsrc/js/application/phortune/phortune-credit-card-form.js' => 'd12d214f', 413 413 'rsrc/js/application/policy/behavior-policy-control.js' => '0eaa33a9', 414 414 'rsrc/js/application/policy/behavior-policy-rule-editor.js' => '9347f172', 415 - 'rsrc/js/application/projects/WorkboardBoard.js' => '44f71637', 415 + 'rsrc/js/application/projects/WorkboardBoard.js' => '34c2f539', 416 416 'rsrc/js/application/projects/WorkboardCard.js' => '0392a5d8', 417 417 'rsrc/js/application/projects/WorkboardCardTemplate.js' => '2a61f8d4', 418 418 'rsrc/js/application/projects/WorkboardColumn.js' => 'c3d24e63', 419 - 'rsrc/js/application/projects/WorkboardController.js' => '42c7a5a7', 419 + 'rsrc/js/application/projects/WorkboardController.js' => 'b9d0c2f3', 420 420 'rsrc/js/application/projects/WorkboardDropEffect.js' => '8e0aa661', 421 421 'rsrc/js/application/projects/WorkboardHeader.js' => '111bfd2d', 422 422 'rsrc/js/application/projects/WorkboardHeaderTemplate.js' => 'ebe83a6b', 423 423 'rsrc/js/application/projects/WorkboardOrderTemplate.js' => '03e8891f', 424 - 'rsrc/js/application/projects/behavior-project-boards.js' => 'aad45445', 424 + 'rsrc/js/application/projects/behavior-project-boards.js' => '58cb6a88', 425 425 'rsrc/js/application/projects/behavior-project-create.js' => '34c53422', 426 426 'rsrc/js/application/projects/behavior-reorder-columns.js' => '8ac32fd9', 427 427 'rsrc/js/application/releeph/releeph-preview-branch.js' => '75184d68', ··· 667 667 'javelin-behavior-phuix-example' => 'c2c500a7', 668 668 'javelin-behavior-policy-control' => '0eaa33a9', 669 669 'javelin-behavior-policy-rule-editor' => '9347f172', 670 - 'javelin-behavior-project-boards' => 'aad45445', 670 + 'javelin-behavior-project-boards' => '58cb6a88', 671 671 'javelin-behavior-project-create' => '34c53422', 672 672 'javelin-behavior-quicksand-blacklist' => '5a6f6a06', 673 673 'javelin-behavior-read-only-warning' => 'b9109f8f', ··· 743 743 'javelin-view-renderer' => '9aae2b66', 744 744 'javelin-view-visitor' => '308f9fe4', 745 745 'javelin-websocket' => 'fdc13e4e', 746 - 'javelin-workboard-board' => '44f71637', 746 + 'javelin-workboard-board' => '34c2f539', 747 747 'javelin-workboard-card' => '0392a5d8', 748 748 'javelin-workboard-card-template' => '2a61f8d4', 749 749 'javelin-workboard-column' => 'c3d24e63', 750 - 'javelin-workboard-controller' => '42c7a5a7', 750 + 'javelin-workboard-controller' => 'b9d0c2f3', 751 751 'javelin-workboard-drop-effect' => '8e0aa661', 752 752 'javelin-workboard-header' => '111bfd2d', 753 753 'javelin-workboard-header-template' => 'ebe83a6b', ··· 1202 1202 'javelin-install', 1203 1203 'javelin-util', 1204 1204 ), 1205 + '34c2f539' => array( 1206 + 'javelin-install', 1207 + 'javelin-dom', 1208 + 'javelin-util', 1209 + 'javelin-stratcom', 1210 + 'javelin-workflow', 1211 + 'phabricator-draggable-list', 1212 + 'javelin-workboard-column', 1213 + 'javelin-workboard-header-template', 1214 + 'javelin-workboard-card-template', 1215 + 'javelin-workboard-order-template', 1216 + ), 1205 1217 '34c53422' => array( 1206 1218 'javelin-behavior', 1207 1219 'javelin-dom', ··· 1264 1276 '4234f572' => array( 1265 1277 'syntax-default-css', 1266 1278 ), 1267 - '42c7a5a7' => array( 1268 - 'javelin-install', 1269 - 'javelin-dom', 1270 - 'javelin-util', 1271 - 'javelin-vector', 1272 - 'javelin-stratcom', 1273 - 'javelin-workflow', 1274 - 'phabricator-drag-and-drop-file-upload', 1275 - 'javelin-workboard-board', 1276 - ), 1277 1279 '4370900d' => array( 1278 1280 'javelin-install', 1279 1281 'javelin-util', ··· 1294 1296 '43bc9360' => array( 1295 1297 'javelin-install', 1296 1298 ), 1297 - '44f71637' => array( 1298 - 'javelin-install', 1299 - 'javelin-dom', 1300 - 'javelin-util', 1301 - 'javelin-stratcom', 1302 - 'javelin-workflow', 1303 - 'phabricator-draggable-list', 1304 - 'javelin-workboard-column', 1305 - 'javelin-workboard-header-template', 1306 - 'javelin-workboard-card-template', 1307 - 'javelin-workboard-order-template', 1308 - ), 1309 1299 '46116c01' => array( 1310 1300 'javelin-request', 1311 1301 'javelin-behavior', ··· 1423 1413 'javelin-stratcom', 1424 1414 'javelin-vector', 1425 1415 'javelin-typeahead-static-source', 1416 + ), 1417 + '58cb6a88' => array( 1418 + 'javelin-behavior', 1419 + 'javelin-dom', 1420 + 'javelin-util', 1421 + 'javelin-vector', 1422 + 'javelin-stratcom', 1423 + 'javelin-workflow', 1424 + 'javelin-workboard-controller', 1425 + 'javelin-workboard-drop-effect', 1426 1426 ), 1427 1427 '5902260c' => array( 1428 1428 'javelin-util', ··· 1852 1852 'javelin-dom', 1853 1853 'javelin-util', 1854 1854 ), 1855 - 'aad45445' => array( 1856 - 'javelin-behavior', 1857 - 'javelin-dom', 1858 - 'javelin-util', 1859 - 'javelin-vector', 1860 - 'javelin-stratcom', 1861 - 'javelin-workflow', 1862 - 'javelin-workboard-controller', 1863 - 'javelin-workboard-drop-effect', 1864 - ), 1865 1855 'ab85e184' => array( 1866 1856 'javelin-install', 1867 1857 'javelin-dom', ··· 1951 1941 'javelin-behavior', 1952 1942 'javelin-uri', 1953 1943 'phabricator-notification', 1944 + ), 1945 + 'b9d0c2f3' => array( 1946 + 'javelin-install', 1947 + 'javelin-dom', 1948 + 'javelin-util', 1949 + 'javelin-vector', 1950 + 'javelin-stratcom', 1951 + 'javelin-workflow', 1952 + 'phabricator-drag-and-drop-file-upload', 1953 + 'javelin-workboard-board', 1954 1954 ), 1955 1955 'bde53589' => array( 1956 1956 'phui-inline-comment-view-css',
+2
src/__phutil_library_map__.php
··· 4163 4163 'PhabricatorProjectBoardFilterController' => 'applications/project/controller/PhabricatorProjectBoardFilterController.php', 4164 4164 'PhabricatorProjectBoardImportController' => 'applications/project/controller/PhabricatorProjectBoardImportController.php', 4165 4165 'PhabricatorProjectBoardManageController' => 'applications/project/controller/PhabricatorProjectBoardManageController.php', 4166 + 'PhabricatorProjectBoardReloadController' => 'applications/project/controller/PhabricatorProjectBoardReloadController.php', 4166 4167 'PhabricatorProjectBoardReorderController' => 'applications/project/controller/PhabricatorProjectBoardReorderController.php', 4167 4168 'PhabricatorProjectBoardViewController' => 'applications/project/controller/PhabricatorProjectBoardViewController.php', 4168 4169 'PhabricatorProjectBuiltinsExample' => 'applications/uiexample/examples/PhabricatorProjectBuiltinsExample.php', ··· 10431 10432 'PhabricatorProjectBoardFilterController' => 'PhabricatorProjectBoardController', 10432 10433 'PhabricatorProjectBoardImportController' => 'PhabricatorProjectBoardController', 10433 10434 'PhabricatorProjectBoardManageController' => 'PhabricatorProjectBoardController', 10435 + 'PhabricatorProjectBoardReloadController' => 'PhabricatorProjectBoardController', 10434 10436 'PhabricatorProjectBoardReorderController' => 'PhabricatorProjectBoardController', 10435 10437 'PhabricatorProjectBoardViewController' => 'PhabricatorProjectBoardController', 10436 10438 'PhabricatorProjectBuiltinsExample' => 'PhabricatorUIExample',
+2
src/applications/project/application/PhabricatorProjectApplication.php
··· 99 99 => 'PhabricatorProjectBoardDefaultController', 100 100 'filter/(?:query/(?P<queryKey>[^/]+)/)?' 101 101 => 'PhabricatorProjectBoardFilterController', 102 + 'reload/' 103 + => 'PhabricatorProjectBoardReloadController', 102 104 ), 103 105 'column/' => array( 104 106 'remove/(?P<id>\d+)/' =>
+38
src/applications/project/controller/PhabricatorProjectBoardReloadController.php
··· 1 + <?php 2 + 3 + final class PhabricatorProjectBoardReloadController 4 + extends PhabricatorProjectBoardController { 5 + 6 + public function handleRequest(AphrontRequest $request) { 7 + $viewer = $request->getViewer(); 8 + 9 + $response = $this->loadProject(); 10 + if ($response) { 11 + return $response; 12 + } 13 + 14 + $project = $this->getProject(); 15 + $state = $this->getViewState(); 16 + $board_uri = $state->newWorkboardURI(); 17 + 18 + $layout_engine = $state->getLayoutEngine(); 19 + 20 + $board_phid = $project->getPHID(); 21 + 22 + $objects = $state->getObjects(); 23 + $object_phids = mpull($objects, 'getPHID'); 24 + 25 + $engine = id(new PhabricatorBoardResponseEngine()) 26 + ->setViewer($viewer) 27 + ->setBoardPHID($board_phid) 28 + ->setUpdatePHIDs($object_phids); 29 + 30 + // TODO: We don't currently process "order" properly. If a user is viewing 31 + // a board grouped by "Owner", and another user changes a task to be owned 32 + // by a user who currently owns nothing on the board, the new header won't 33 + // generate correctly if the first user presses "R". 34 + 35 + return $engine->buildResponse(); 36 + } 37 + 38 + }
+1
src/applications/project/controller/PhabricatorProjectBoardViewController.php
··· 286 286 'moveURI' => $this->getApplicationURI('move/'.$project->getID().'/'), 287 287 'uploadURI' => '/file/dropupload/', 288 288 'coverURI' => $this->getApplicationURI('cover/'), 289 + 'reloadURI' => phutil_string_cast($state->newWorkboardURI('reload/')), 289 290 'chunkThreshold' => PhabricatorFileStorageEngine::getChunkThreshold(), 290 291 'pointsEnabled' => ManiphestTaskPoints::getIsEnabled(), 291 292
+96 -47
src/applications/project/engine/PhabricatorBoardResponseEngine.php
··· 6 6 private $boardPHID; 7 7 private $objectPHID; 8 8 private $visiblePHIDs; 9 + private $updatePHIDs = array(); 9 10 private $ordering; 10 11 private $sounds; 11 12 ··· 45 46 return $this->visiblePHIDs; 46 47 } 47 48 49 + public function setUpdatePHIDs(array $update_phids) { 50 + $this->updatePHIDs = $update_phids; 51 + return $this; 52 + } 53 + 54 + public function getUpdatePHIDs() { 55 + return $this->updatePHIDs; 56 + } 57 + 48 58 public function setOrdering(PhabricatorProjectColumnOrder $ordering) { 49 59 $this->ordering = $ordering; 50 60 return $this; ··· 71 81 72 82 // Load all the other tasks that are visible in the affected columns and 73 83 // perform layout for them. 74 - $visible_phids = $this->getAllVisiblePHIDs(); 84 + $all_phids = $this->getAllVisiblePHIDs(); 75 85 76 86 $layout_engine = id(new PhabricatorBoardLayoutEngine()) 77 87 ->setViewer($viewer) 78 88 ->setBoardPHIDs(array($board_phid)) 79 - ->setObjectPHIDs($visible_phids) 89 + ->setObjectPHIDs($all_phids) 80 90 ->executeLayout(); 81 - 82 - $object_columns = $layout_engine->getObjectColumns( 83 - $board_phid, 84 - $object_phid); 85 91 86 92 $natural = array(); 87 - foreach ($object_columns as $column_phid => $column) { 93 + 94 + $update_phids = $this->getAllUpdatePHIDs(); 95 + $update_columns = array(); 96 + foreach ($update_phids as $update_phid) { 97 + $update_columns += $layout_engine->getObjectColumns( 98 + $board_phid, 99 + $update_phid); 100 + } 101 + 102 + foreach ($update_columns as $column_phid => $column) { 88 103 $column_object_phids = $layout_engine->getColumnObjectPHIDs( 89 104 $board_phid, 90 105 $column_phid); 91 106 $natural[$column_phid] = array_values($column_object_phids); 92 107 } 93 108 94 - $all_visible = id(new ManiphestTaskQuery()) 109 + $all_objects = id(new ManiphestTaskQuery()) 95 110 ->setViewer($viewer) 96 - ->withPHIDs($visible_phids) 111 + ->withPHIDs($all_phids) 97 112 ->execute(); 98 - $all_visible = mpull($all_visible, null, 'getPHID'); 113 + $all_objects = mpull($all_objects, null, 'getPHID'); 99 114 100 115 if ($ordering) { 101 - $vectors = $ordering->getSortVectorsForObjects($all_visible); 102 - $header_keys = $ordering->getHeaderKeysForObjects($all_visible); 103 - $headers = $ordering->getHeadersForObjects($all_visible); 116 + $vectors = $ordering->getSortVectorsForObjects($all_objects); 117 + $header_keys = $ordering->getHeaderKeysForObjects($all_objects); 118 + $headers = $ordering->getHeadersForObjects($all_objects); 104 119 $headers = mpull($headers, 'toDictionary'); 105 120 } else { 106 121 $vectors = array(); ··· 108 123 $headers = array(); 109 124 } 110 125 111 - $object = id(new ManiphestTaskQuery()) 112 - ->setViewer($viewer) 113 - ->withPHIDs(array($object_phid)) 114 - ->needProjectPHIDs(true) 115 - ->executeOne(); 116 - if (!$object) { 117 - return new Aphront404Response(); 118 - } 119 - 120 - $template = $this->buildTemplate($object); 126 + $templates = $this->newCardTemplates(); 121 127 122 128 $cards = array(); 123 - foreach ($all_visible as $card_phid => $object) { 129 + foreach ($all_objects as $card_phid => $object) { 124 130 $card = array( 125 131 'vectors' => array(), 126 132 'headers' => array(), ··· 144 150 $card['properties'] = self::newTaskProperties($object); 145 151 } 146 152 147 - if ($card_phid === $object_phid) { 148 - $card['nodeHTMLTemplate'] = hsprintf('%s', $template); 153 + if (isset($templates[$card_phid])) { 154 + $card['nodeHTMLTemplate'] = hsprintf('%s', $templates[$card_phid]); 155 + $card['update'] = true; 156 + } else { 157 + $card['update'] = false; 149 158 } 150 159 151 160 $card['vectors'] = (object)$card['vectors']; ··· 156 165 } 157 166 158 167 $payload = array( 159 - 'objectPHID' => $object_phid, 160 168 'columnMaps' => $natural, 161 169 'cards' => $cards, 162 170 'headers' => $headers, ··· 176 184 ); 177 185 } 178 186 179 - private function buildTemplate($object) { 180 - $viewer = $this->getViewer(); 181 - $object_phid = $this->getObjectPHID(); 182 - 183 - $excluded_phids = $this->loadExcludedProjectPHIDs(); 184 - 185 - $rendering_engine = id(new PhabricatorBoardRenderingEngine()) 186 - ->setViewer($viewer) 187 - ->setObjects(array($object)) 188 - ->setExcludedProjectPHIDs($excluded_phids); 189 - 190 - $card = $rendering_engine->renderCard($object_phid); 191 - 192 - return hsprintf('%s', $card->getItem()); 193 - } 194 - 195 187 private function loadExcludedProjectPHIDs() { 196 188 $viewer = $this->getViewer(); 197 189 $board_phid = $this->getBoardPHID(); ··· 211 203 } 212 204 213 205 private function getAllVisiblePHIDs() { 214 - $visible_phids = $this->getVisiblePHIDs(); 215 - $visible_phids[] = $this->getObjectPHID(); 216 - $visible_phids = array_fuse($visible_phids); 217 - return $visible_phids; 206 + $phids = $this->getAllUpdatePHIDs(); 207 + 208 + foreach ($this->getVisiblePHIDs() as $phid) { 209 + $phids[] = $phid; 210 + } 211 + 212 + $phids = array_fuse($phids); 213 + 214 + return $phids; 215 + } 216 + 217 + private function getAllUpdatePHIDs() { 218 + $phids = $this->getUpdatePHIDs(); 219 + 220 + $object_phid = $this->getObjectPHID(); 221 + if ($object_phid) { 222 + $phids[] = $object_phid; 223 + } 224 + 225 + $phids = array_fuse($phids); 226 + 227 + return $phids; 228 + } 229 + 230 + private function newCardTemplates() { 231 + $viewer = $this->getViewer(); 232 + 233 + $update_phids = $this->getAllUpdatePHIDs(); 234 + if (!$update_phids) { 235 + return array(); 236 + } 237 + 238 + $objects = id(new ManiphestTaskQuery()) 239 + ->setViewer($viewer) 240 + ->withPHIDs($update_phids) 241 + ->needProjectPHIDs(true) 242 + ->execute(); 243 + 244 + if (!$objects) { 245 + return array(); 246 + } 247 + 248 + $excluded_phids = $this->loadExcludedProjectPHIDs(); 249 + 250 + $rendering_engine = id(new PhabricatorBoardRenderingEngine()) 251 + ->setViewer($viewer) 252 + ->setObjects($objects) 253 + ->setExcludedProjectPHIDs($excluded_phids); 254 + 255 + $templates = array(); 256 + foreach ($objects as $object) { 257 + $object_phid = $object->getPHID(); 258 + 259 + $card = $rendering_engine->renderCard($object_phid); 260 + $item = $card->getItem(); 261 + $template = hsprintf('%s', $item); 262 + 263 + $templates[$object_phid] = $template; 264 + } 265 + 266 + return $templates; 218 267 } 219 268 220 269 }
+104 -44
webroot/rsrc/js/application/projects/WorkboardBoard.js
··· 129 129 start: function() { 130 130 this._setupDragHandlers(); 131 131 132 + // TODO: This is temporary code to make it easier to debug this workflow 133 + // by pressing the "R" key. 134 + var on_reload = JX.bind(this, this._reloadCards); 135 + new JX.KeyboardShortcut('R', 'Reload Card State (Prototype)') 136 + .setHandler(on_reload) 137 + .register(); 138 + 132 139 for (var k in this._columns) { 133 140 this._columns[k].redraw(); 134 141 } ··· 551 558 }, 552 559 553 560 _oncardupdate: function(list, src_phid, dst_phid, after_phid, response) { 554 - var src_column = this.getColumn(src_phid); 555 - var dst_column = this.getColumn(dst_phid); 556 - 557 - var card = src_column.removeCard(response.objectPHID); 558 - dst_column.addCard(card, after_phid); 559 - 560 - src_column.markForRedraw(); 561 - dst_column.markForRedraw(); 562 - 563 561 this.updateCard(response); 564 562 565 563 var sounds = response.sounds || []; ··· 572 570 573 571 updateCard: function(response) { 574 572 var columns = this.getColumns(); 573 + var column_phid; 574 + var card_phid; 575 + var card_data; 575 576 576 - var phid = response.objectPHID; 577 + // The server may send us a full or partial update for a card. If we've 578 + // received a full update, we're going to redraw the entire card and may 579 + // need to change which columns it appears in. 577 580 578 - for (var add_phid in response.columnMaps) { 579 - var target_column = this.getColumn(add_phid); 581 + // For a partial update, we've just received supplemental sorting or 582 + // property information and do not need to perform a full redraw. 583 + 584 + // When we reload card state, edit a card, or move a card, we get a full 585 + // update for the card. 586 + 587 + // Ween we move a card in a column, we may get a partial update for other 588 + // visible cards in the column. 589 + 590 + 591 + // Figure out which columns each card now appears in. For cards that 592 + // have received a full update, we'll use this map to move them into 593 + // the correct columns. 594 + var update_map = {}; 595 + for (column_phid in response.columnMaps) { 596 + var target_column = this.getColumn(column_phid); 580 597 581 598 if (!target_column) { 582 599 // If the column isn't visible, don't try to add a card to it. 583 600 continue; 584 601 } 585 602 586 - target_column.newCard(phid); 587 - } 603 + var column_map = response.columnMaps[column_phid]; 588 604 589 - var column_maps = response.columnMaps; 590 - var natural_column; 591 - for (var natural_phid in column_maps) { 592 - natural_column = this.getColumn(natural_phid); 593 - if (!natural_column) { 594 - // Our view of the board may be out of date, so we might get back 595 - // information about columns that aren't visible. Just ignore the 596 - // position information for any columns we aren't displaying on the 597 - // client. 598 - continue; 605 + for (var ii = 0; ii < column_map.length; ii++) { 606 + card_phid = column_map[ii]; 607 + if (!update_map[card_phid]) { 608 + update_map[card_phid] = {}; 609 + } 610 + update_map[card_phid][column_phid] = true; 599 611 } 600 - 601 - natural_column.setNaturalOrder(column_maps[natural_phid]); 602 612 } 603 613 604 - for (var card_phid in response.cards) { 605 - var card_data = response.cards[card_phid]; 614 + // Process partial updates for cards. This is supplemental data which 615 + // we can just merge in without any special handling. 616 + for (card_phid in response.cards) { 617 + card_data = response.cards[card_phid]; 606 618 var card_template = this.getCardTemplate(card_phid); 607 619 608 620 if (card_data.nodeHTMLTemplate) { ··· 623 635 } 624 636 } 625 637 638 + 639 + // Process full updates for cards which we have a full update for. This 640 + // may involve moving them between columns. 641 + for (card_phid in response.cards) { 642 + card_data = response.cards[card_phid]; 643 + 644 + if (!card_data.update) { 645 + continue; 646 + } 647 + 648 + for (column_phid in columns) { 649 + var column = columns[column_phid]; 650 + var card = column.getCard(card_phid); 651 + 652 + if (card) { 653 + card.redraw(); 654 + column.markForRedraw(); 655 + } 656 + 657 + // Compare the server state to the client state, and add or remove 658 + // cards on the client as necessary to synchronize them. 659 + 660 + if (update_map[card_phid][column_phid]) { 661 + if (!card) { 662 + column.newCard(card_phid); 663 + column.markForRedraw(); 664 + } 665 + } else { 666 + if (card) { 667 + column.removeCard(card_phid); 668 + column.markForRedraw(); 669 + } 670 + } 671 + } 672 + } 673 + 674 + var column_maps = response.columnMaps; 675 + var natural_column; 676 + for (var natural_phid in column_maps) { 677 + natural_column = this.getColumn(natural_phid); 678 + if (!natural_column) { 679 + // Our view of the board may be out of date, so we might get back 680 + // information about columns that aren't visible. Just ignore the 681 + // position information for any columns we aren't displaying on the 682 + // client. 683 + continue; 684 + } 685 + 686 + natural_column.setNaturalOrder(column_maps[natural_phid]); 687 + } 688 + 626 689 var headers = response.headers; 627 690 for (var jj = 0; jj < headers.length; jj++) { 628 691 var header = headers[jj]; ··· 634 697 .setEditProperties(header.editProperties); 635 698 } 636 699 637 - for (var column_phid in columns) { 638 - var column = columns[column_phid]; 639 - 640 - var cards = column.getCards(); 641 - for (var object_phid in cards) { 642 - if (object_phid !== phid) { 643 - continue; 644 - } 645 - 646 - var card = cards[object_phid]; 647 - card.redraw(); 648 - 649 - column.markForRedraw(); 650 - } 651 - } 652 - 653 700 this._redrawColumns(); 654 701 }, 655 702 ··· 660 707 columns[k].redraw(); 661 708 } 662 709 } 710 + }, 711 + 712 + _reloadCards: function() { 713 + var data = {}; 714 + var on_reload = JX.bind(this, this._onReloadResponse); 715 + 716 + new JX.Request(this.getController().getReloadURI(), on_reload) 717 + .setData(data) 718 + .send(); 719 + }, 720 + 721 + _onReloadResponse: function(response) { 722 + this.updateCard(response); 663 723 } 664 724 665 725 }
+1
webroot/rsrc/js/application/projects/WorkboardController.js
··· 21 21 uploadURI: null, 22 22 coverURI: null, 23 23 moveURI: null, 24 + reloadURI: null, 24 25 chunkThreshold: null 25 26 }, 26 27
+1
webroot/rsrc/js/application/projects/behavior-project-boards.js
··· 71 71 .setUploadURI(config.uploadURI) 72 72 .setCoverURI(config.coverURI) 73 73 .setMoveURI(config.moveURI) 74 + .setReloadURI(config.reloadURI) 74 75 .setChunkThreshold(config.chunkThreshold) 75 76 .start(); 76 77 }