@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

When a task card is edited, emit update events for old boards and parent boards

Summary:
Ref T4900. When a card is edited, we currently emit an update notification for all the projects the task is tagged with. This isn't quite the right set:

- We want to emit notifications for projects the task //was previously// tagged with, so it can be removed from boards it should no longer be part of.
- We want to emit notifications for ancestors of projects the task is or was tagged with, so parent project boards can be updated.
- However, we don't need to emit notifications for projects that don't actually have workboards.

Adjust the notification set to align better to these rules.

Test Plan:
- Removal of Parent Project: Edited a task on board "A > B", removing the "B" project tag. Saw board A update in another window.
- Normal Update: Edited a task title on board X, saw board X update in another window.
- Used `bin/aphlict debug` to inspect the notification set, saw generally sensible-seeming data going over the wire.

Reviewers: amckinley

Maniphest Tasks: T4900

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

+78 -32
+14 -14
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' => '75727403', 415 + 'rsrc/js/application/projects/WorkboardBoard.js' => 'b46d88c5', 416 416 'rsrc/js/application/projects/WorkboardCard.js' => '0392a5d8', 417 417 'rsrc/js/application/projects/WorkboardCardTemplate.js' => '84f82dad', 418 418 'rsrc/js/application/projects/WorkboardColumn.js' => 'c3d24e63', ··· 743 743 'javelin-view-renderer' => '9aae2b66', 744 744 'javelin-view-visitor' => '308f9fe4', 745 745 'javelin-websocket' => 'fdc13e4e', 746 - 'javelin-workboard-board' => '75727403', 746 + 'javelin-workboard-board' => 'b46d88c5', 747 747 'javelin-workboard-card' => '0392a5d8', 748 748 'javelin-workboard-card-template' => '84f82dad', 749 749 'javelin-workboard-column' => 'c3d24e63', ··· 1549 1549 'javelin-uri', 1550 1550 'javelin-request', 1551 1551 ), 1552 - 75727403 => array( 1553 - 'javelin-install', 1554 - 'javelin-dom', 1555 - 'javelin-util', 1556 - 'javelin-stratcom', 1557 - 'javelin-workflow', 1558 - 'phabricator-draggable-list', 1559 - 'javelin-workboard-column', 1560 - 'javelin-workboard-header-template', 1561 - 'javelin-workboard-card-template', 1562 - 'javelin-workboard-order-template', 1563 - ), 1564 1552 '78bc5d94' => array( 1565 1553 'javelin-behavior', 1566 1554 'javelin-uri', ··· 1899 1887 ), 1900 1888 'b347a301' => array( 1901 1889 'javelin-behavior', 1890 + ), 1891 + 'b46d88c5' => array( 1892 + 'javelin-install', 1893 + 'javelin-dom', 1894 + 'javelin-util', 1895 + 'javelin-stratcom', 1896 + 'javelin-workflow', 1897 + 'phabricator-draggable-list', 1898 + 'javelin-workboard-column', 1899 + 'javelin-workboard-header-template', 1900 + 'javelin-workboard-card-template', 1901 + 'javelin-workboard-order-template', 1902 1902 ), 1903 1903 'b49fd60c' => array( 1904 1904 'multirow-row-manager',
+59 -17
src/applications/maniphest/editor/ManiphestTransactionEditor.php
··· 3 3 final class ManiphestTransactionEditor 4 4 extends PhabricatorApplicationTransactionEditor { 5 5 6 + private $oldProjectPHIDs; 6 7 private $moreValidationErrors = array(); 7 8 8 9 public function getEditorApplicationClass() { ··· 376 377 '+' => array($actor_phid => $actor_phid), 377 378 )); 378 379 } 380 + } 381 + 382 + $send_notifications = PhabricatorNotificationClient::isEnabled(); 383 + if ($send_notifications) { 384 + $this->oldProjectPHIDs = $this->loadProjectPHIDs($object); 379 385 } 380 386 381 387 return $results; ··· 859 865 return array_values($phid_list); 860 866 } 861 867 868 + protected function didApplyTransactions($object, array $xactions) { 869 + $send_notifications = PhabricatorNotificationClient::isEnabled(); 870 + if ($send_notifications) { 871 + $old_phids = $this->oldProjectPHIDs; 872 + $new_phids = $this->loadProjectPHIDs($object); 873 + 874 + // We want to emit update notifications for all old and new tagged 875 + // projects, and all parents of those projects. For example, if an 876 + // edit removes project "A > B" from a task, the "A" workboard should 877 + // receive an update event. 878 + 879 + $project_phids = array_fuse($old_phids) + array_fuse($new_phids); 880 + $project_phids = array_keys($project_phids); 881 + 882 + $projects = id(new PhabricatorProjectQuery()) 883 + ->setViewer(PhabricatorUser::getOmnipotentUser()) 884 + ->withPHIDs($project_phids) 885 + ->execute(); 862 886 863 - protected function didApplyTransactions($object, array $xactions) { 864 - // TODO: This should include projects which the object was previously 865 - // associated with but no longer is (so it can be removed from those 866 - // boards) but currently does not. 887 + $notify_projects = array(); 888 + foreach ($projects as $project) { 889 + $notify_projects[$project->getPHID()] = $project; 890 + foreach ($project->getAncestorProjects() as $ancestor) { 891 + $notify_projects[$ancestor->getPHID()] = $ancestor; 892 + } 893 + } 894 + 895 + foreach ($notify_projects as $key => $project) { 896 + if (!$project->getHasWorkboard()) { 897 + unset($notify_projects[$key]); 898 + } 899 + } 900 + 901 + $notify_phids = array_keys($notify_projects); 902 + 903 + if ($notify_phids) { 904 + $data = array( 905 + 'type' => 'workboards', 906 + 'subscribers' => $notify_phids, 907 + ); 908 + 909 + PhabricatorNotificationClient::tryToPostMessage($data); 910 + } 911 + } 912 + 913 + return $xactions; 914 + } 915 + 916 + private function loadProjectPHIDs(ManiphestTask $task) { 917 + if (!$task->getPHID()) { 918 + return array(); 919 + } 867 920 868 921 $edge_query = id(new PhabricatorEdgeQuery()) 869 - ->withSourcePHIDs(array($object->getPHID())) 922 + ->withSourcePHIDs(array($task->getPHID())) 870 923 ->withEdgeTypes( 871 924 array( 872 925 PhabricatorProjectObjectHasProjectEdgeType::EDGECONST, ··· 874 927 875 928 $edge_query->execute(); 876 929 877 - $project_phids = $edge_query->getDestinationPHIDs(); 878 - 879 - if ($project_phids) { 880 - $data = array( 881 - 'type' => 'workboards', 882 - 'subscribers' => $project_phids, 883 - ); 884 - 885 - PhabricatorNotificationClient::tryToPostMessage($data); 886 - } 887 - 888 - return $xactions; 930 + return $edge_query->getDestinationPHIDs(); 889 931 } 890 932 891 933 }
+4
src/applications/notification/client/PhabricatorNotificationClient.php
··· 37 37 } 38 38 } 39 39 40 + public static function isEnabled() { 41 + return (bool)PhabricatorNotificationServerRef::getEnabledAdminServers(); 42 + } 43 + 40 44 }
+1 -1
webroot/rsrc/js/application/projects/WorkboardBoard.js
··· 711 711 // Compare the server state to the client state, and add or remove 712 712 // cards on the client as necessary to synchronize them. 713 713 714 - if (update_map[card_phid][column_phid]) { 714 + if (update_map[card_phid] && update_map[card_phid][column_phid]) { 715 715 if (!card) { 716 716 column.newCard(card_phid); 717 717 column.markForRedraw();