@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.

Subscriptions - make a dialog for massive subscription lists

Summary: Ref T4430. This just deploys it on the property lists. (Help on how to do translations better? I tried a more traditional pht('%s, %s, %s, and %d other(s)') but I think the string lookup assumes the %d comes as the second param or something?)

Test Plan: Made a Maniphest Task with a hojillion subscribers and noted the working dialogue. Also made a Pholio Mock with lots of subscribers and it worked.

Reviewers: epriestley

Reviewed By: epriestley

Subscribers: aran, epriestley, Korvin, chad

Maniphest Tasks: T4430

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

+230 -11
+2
resources/celerity/map.php
··· 109 109 'rsrc/css/application/search/search-results.css' => 'f240504c', 110 110 'rsrc/css/application/settings/settings.css' => 'ea8f5915', 111 111 'rsrc/css/application/slowvote/slowvote.css' => '266df6a1', 112 + 'rsrc/css/application/subscriptions/subscribers-list.css' => '5bb30c78', 112 113 'rsrc/css/application/tokens/tokens.css' => 'fb286311', 113 114 'rsrc/css/application/uiexample/example.css' => '4741b891', 114 115 'rsrc/css/core/core.css' => 'da26ddb2', ··· 804 805 'sprite-projects-css' => '7578fa56', 805 806 'sprite-status-css' => '8bce1c97', 806 807 'sprite-tokens-css' => '1706b943', 808 + 'subscribers-list-css' => '5bb30c78', 807 809 'syntax-highlighting-css' => '3c18c1cb', 808 810 'tokens-css' => 'fb286311', 809 811 ),
+4
src/__phutil_library_map__.php
··· 2092 2092 'PhabricatorSubscribersQuery' => 'applications/subscriptions/query/PhabricatorSubscribersQuery.php', 2093 2093 'PhabricatorSubscriptionsEditController' => 'applications/subscriptions/controller/PhabricatorSubscriptionsEditController.php', 2094 2094 'PhabricatorSubscriptionsEditor' => 'applications/subscriptions/editor/PhabricatorSubscriptionsEditor.php', 2095 + 'PhabricatorSubscriptionsListController' => 'applications/subscriptions/controller/PhabricatorSubscriptionsListController.php', 2095 2096 'PhabricatorSubscriptionsUIEventListener' => 'applications/subscriptions/events/PhabricatorSubscriptionsUIEventListener.php', 2096 2097 'PhabricatorSymbolNameLinter' => 'infrastructure/lint/hook/PhabricatorSymbolNameLinter.php', 2097 2098 'PhabricatorSyntaxHighlighter' => 'infrastructure/markup/PhabricatorSyntaxHighlighter.php', ··· 2521 2522 'SleepBuildStepImplementation' => 'applications/harbormaster/step/SleepBuildStepImplementation.php', 2522 2523 'SlowvoteEmbedView' => 'applications/slowvote/view/SlowvoteEmbedView.php', 2523 2524 'SlowvoteRemarkupRule' => 'applications/slowvote/remarkup/SlowvoteRemarkupRule.php', 2525 + 'SubscriptionListDialogBuilder' => 'applications/subscriptions/view/SubscriptionListDialogBuilder.php', 2526 + 'SubscriptionListStringBuilder' => 'applications/subscriptions/view/SubscriptionListStringBuilder.php', 2524 2527 'UploadArtifactBuildStepImplementation' => 'applications/harbormaster/step/UploadArtifactBuildStepImplementation.php', 2525 2528 'VariableBuildStepImplementation' => 'applications/harbormaster/step/VariableBuildStepImplementation.php', 2526 2529 'WaitForPreviousBuildStepImplementation' => 'applications/harbormaster/step/WaitForPreviousBuildStepImplementation.php', ··· 4889 4892 'PhabricatorSubscribersQuery' => 'PhabricatorQuery', 4890 4893 'PhabricatorSubscriptionsEditController' => 'PhabricatorController', 4891 4894 'PhabricatorSubscriptionsEditor' => 'PhabricatorEditor', 4895 + 'PhabricatorSubscriptionsListController' => 'PhabricatorController', 4892 4896 'PhabricatorSubscriptionsUIEventListener' => 'PhabricatorEventListener', 4893 4897 'PhabricatorSymbolNameLinter' => 'ArcanistXHPASTLintNamingHook', 4894 4898 'PhabricatorSyntaxHighlightingConfigOptions' => 'PhabricatorApplicationConfigOptions',
+7 -5
src/applications/maniphest/controller/ManiphestTaskDetailController.php
··· 516 516 pht('Priority'), 517 517 ManiphestTaskPriority::getTaskPriorityName($task->getPriority())); 518 518 519 - $view->addProperty( 520 - pht('Subscribers'), 521 - $task->getCCPHIDs() 522 - ? $this->renderHandlesForPHIDs($task->getCCPHIDs(), ',') 523 - : phutil_tag('em', array(), pht('None'))); 519 + $handles = $this->getLoadedHandles(); 520 + $cc_handles = array_select_keys($handles, $task->getCCPHIDs()); 521 + $subscriber_html = id(new SubscriptionListStringBuilder()) 522 + ->setObjectPHID($task->getPHID()) 523 + ->setHandles($cc_handles) 524 + ->buildPropertyString(); 525 + $view->addProperty(pht('Subscribers'), $subscriber_html); 524 526 525 527 $view->addProperty( 526 528 pht('Author'),
+1
src/applications/subscriptions/application/PhabricatorApplicationSubscriptions.php
··· 21 21 '/subscriptions/' => array( 22 22 '(?P<action>add|delete)/'. 23 23 '(?P<phid>[^/]+)/' => 'PhabricatorSubscriptionsEditController', 24 + 'list/(?P<phid>[^/]+)/' => 'PhabricatorSubscriptionsListController', 24 25 ), 25 26 ); 26 27 }
+49
src/applications/subscriptions/controller/PhabricatorSubscriptionsListController.php
··· 1 + <?php 2 + 3 + final class PhabricatorSubscriptionsListController 4 + extends PhabricatorController { 5 + 6 + private $phid; 7 + 8 + public function willProcessRequest(array $data) { 9 + $this->phid = idx($data, 'phid'); 10 + } 11 + 12 + public function processRequest() { 13 + $request = $this->getRequest(); 14 + 15 + $viewer = $request->getUser(); 16 + $phid = $this->phid; 17 + 18 + $object = id(new PhabricatorObjectQuery()) 19 + ->setViewer($viewer) 20 + ->withPHIDs(array($phid)) 21 + ->executeOne(); 22 + 23 + if ($object instanceof PhabricatorSubscribableInterface) { 24 + $subscriber_phids = PhabricatorSubscribersQuery::loadSubscribersForPHID( 25 + $phid); 26 + } else if ($object instanceof ManiphestTask) { 27 + $subscriber_phids = $object->getCCPHIDs(); 28 + } 29 + 30 + $handle_phids = $subscriber_phids; 31 + $handle_phids[] = $phid; 32 + 33 + $handles = id(new PhabricatorHandleQuery()) 34 + ->setViewer($viewer) 35 + ->withPHIDs($handle_phids) 36 + ->execute(); 37 + $object_handle = $handles[$phid]; 38 + 39 + $dialog = id(new SubscriptionListDialogBuilder()) 40 + ->setViewer($viewer) 41 + ->setTitle(pht('Subscribers for %s', $object_handle->getFullName())) 42 + ->setObjectPHID($phid) 43 + ->setHandles($handles) 44 + ->buildDialog(); 45 + 46 + return id(new AphrontDialogResponse())->setDialog($dialog); 47 + } 48 + 49 + }
+5 -6
src/applications/subscriptions/events/PhabricatorSubscriptionsUIEventListener.php
··· 113 113 ->setViewer($user) 114 114 ->withPHIDs($subscribers) 115 115 ->execute(); 116 - $sub_view = array(); 117 - foreach ($subscribers as $subscriber) { 118 - $sub_view[] = $handles[$subscriber]->renderLink(); 119 - } 120 - $sub_view = phutil_implode_html(', ', $sub_view); 121 116 } else { 122 - $sub_view = phutil_tag('em', array(), pht('None')); 117 + $handles = array(); 123 118 } 119 + $sub_view = id(new SubscriptionListStringBuilder()) 120 + ->setObjectPHID($object->getPHID()) 121 + ->setHandles($handles) 122 + ->buildPropertyString(); 124 123 125 124 $view = $event->getValue('view'); 126 125 $view->addProperty(pht('Subscribers'), $sub_view);
+78
src/applications/subscriptions/view/SubscriptionListDialogBuilder.php
··· 1 + <?php 2 + 3 + final class SubscriptionListDialogBuilder { 4 + 5 + private $viewer; 6 + private $handles; 7 + private $objectPHID; 8 + private $title; 9 + 10 + public function setViewer(PhabricatorUser $viewer) { 11 + $this->viewer = $viewer; 12 + return $this; 13 + } 14 + 15 + public function getViewer() { 16 + return $this->viewer; 17 + } 18 + 19 + public function setHandles(array $handles) { 20 + assert_instances_of($handles, 'PhabricatorObjectHandle'); 21 + $this->handles = $handles; 22 + return $this; 23 + } 24 + 25 + public function getHandles() { 26 + return $this->handles; 27 + } 28 + 29 + public function setObjectPHID($object_phid) { 30 + $this->objectPHID = $object_phid; 31 + return $this; 32 + } 33 + 34 + public function getObjectPHID() { 35 + return $this->objectPHID; 36 + } 37 + 38 + public function setTitle($title) { 39 + $this->title = $title; 40 + return $this; 41 + } 42 + 43 + public function getTitle() { 44 + return $this->title; 45 + } 46 + 47 + public function buildDialog() { 48 + $phid = $this->getObjectPHID(); 49 + $handles = $this->getHandles(); 50 + $object_handle = $handles[$phid]; 51 + unset($handles[$phid]); 52 + 53 + require_celerity_resource('subscribers-list-css'); 54 + return id(new AphrontDialogView()) 55 + ->setUser($this->getViewer()) 56 + ->setClass('subscriber-list-dialog') 57 + ->setTitle($this->getTitle()) 58 + ->appendChild($this->buildBody($this->getViewer(), $handles)) 59 + ->addCancelButton($object_handle->getURI(), pht('Dismiss')); 60 + } 61 + 62 + private function buildBody(PhabricatorUser $viewer, array $handles) { 63 + 64 + $list = id(new PHUIObjectItemListView()) 65 + ->setUser($viewer); 66 + foreach ($handles as $handle) { 67 + // TODO - include $handle image - T4400 68 + $item = id(new PHUIObjectItemView()) 69 + ->setHeader($handle->getFullName()) 70 + ->setHref($handle->getURI()) 71 + ->setDisabled($handle->isDisabled()); 72 + $list->addItem($item); 73 + } 74 + 75 + return $list; 76 + } 77 + 78 + }
+64
src/applications/subscriptions/view/SubscriptionListStringBuilder.php
··· 1 + <?php 2 + 3 + final class SubscriptionListStringBuilder { 4 + 5 + private $handles; 6 + private $objectPHID; 7 + 8 + public function setHandles(array $handles) { 9 + assert_instances_of($handles, 'PhabricatorObjectHandle'); 10 + $this->handles = $handles; 11 + return $this; 12 + } 13 + 14 + public function getHandles() { 15 + return $this->handles; 16 + } 17 + 18 + public function setObjectPHID($object_phid) { 19 + $this->objectPHID = $object_phid; 20 + return $this; 21 + } 22 + 23 + public function getObjectPHID() { 24 + return $this->objectPHID; 25 + } 26 + 27 + public function buildPropertyString() { 28 + $phid = $this->getObjectPHID(); 29 + $handles = $this->getHandles(); 30 + 31 + if (!$handles) { 32 + return phutil_tag('em', array(), pht('None')); 33 + } 34 + 35 + $html = array(); 36 + $show_count = 3; 37 + $subscribers_count = count($handles); 38 + if ($subscribers_count <= $show_count) { 39 + return phutil_implode_html(', ', mpull($handles, 'renderLink')); 40 + } 41 + 42 + $args = array('%s, %s, %s, and %s'); 43 + $shown = 0; 44 + foreach ($handles as $handle) { 45 + $shown++; 46 + if ($shown > $show_count) { 47 + break; 48 + } 49 + $args[] = $handle->renderLink(); 50 + } 51 + $not_shown_count = $subscribers_count - $show_count; 52 + $not_shown_txt = pht('%d other(s)', $not_shown_count); 53 + $args[] = javelin_tag( 54 + 'a', 55 + array( 56 + 'href' => '/subscriptions/list/'.$phid.'/', 57 + 'sigil' => 'workflow' 58 + ), 59 + $not_shown_txt); 60 + 61 + return call_user_func_array('pht', $args); 62 + } 63 + 64 + }
+5
src/infrastructure/internationalization/translation/PhabricatorBaseEnglishTranslation.php
··· 541 541 ), 542 542 ), 543 543 544 + '%d other(s)' => array( 545 + '1 other', 546 + '%d others', 547 + ), 548 + 544 549 '%s edited subscriber(s), added %d: %s; removed %d: %s.' => 545 550 '%s edited subscribers, added: %3$s; removed: %5$s', 546 551
+15
webroot/rsrc/css/application/subscriptions/subscribers-list.css
··· 1 + /** 2 + * @provides subscribers-list-css 3 + */ 4 + 5 + .subscriber-list-dialog { 6 + width: 400px; 7 + } 8 + 9 + .subscriber-list-dialog .aphront-dialog-body { 10 + padding: 0; 11 + } 12 + 13 + .subscriber-list-dialog .phui-object-item-list-view { 14 + margin: 0; 15 + }