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

Allow "Custom" policies to be selected in the policy control

Summary: Ref T603. When a user selects "Custom", we pop open the rules dialog and let them create a new rule or edit the existing rule.

Test Plan: Set some objects to have custom policies.

Reviewers: btrahan

Reviewed By: btrahan

CC: aran

Maniphest Tasks: T603

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

+135 -15
+2 -1
src/__celerity_resource_map__.php
··· 2295 2295 ), 2296 2296 'javelin-behavior-policy-control' => 2297 2297 array( 2298 - 'uri' => '/res/f43ba427/rsrc/js/application/policy/behavior-policy-control.js', 2298 + 'uri' => '/res/ce9f54c8/rsrc/js/application/policy/behavior-policy-control.js', 2299 2299 'type' => 'js', 2300 2300 'requires' => 2301 2301 array( ··· 2304 2304 2 => 'javelin-util', 2305 2305 3 => 'phabricator-dropdown-menu', 2306 2306 4 => 'phabricator-menu-item', 2307 + 5 => 'javelin-workflow', 2307 2308 ), 2308 2309 'disk' => '/rsrc/js/application/policy/behavior-policy-control.js', 2309 2310 ),
+10 -2
src/applications/meta/controller/PhabricatorApplicationEditController.php
··· 47 47 } 48 48 49 49 if (empty($policies[$new])) { 50 - // Can't set the policy to something invalid. 51 - continue; 50 + // Not a standard policy, check for a custom policy. 51 + $policy = id(new PhabricatorPolicyQuery()) 52 + ->setViewer($user) 53 + ->withPHIDs(array($new)) 54 + ->executeOne(); 55 + if (!$policy) { 56 + // Not a custom policy either. Can't set the policy to something 57 + // invalid, so skip this. 58 + continue; 59 + } 52 60 } 53 61 54 62 if ($new == PhabricatorPolicies::POLICY_PUBLIC) {
+1 -1
src/applications/policy/rule/PhabricatorPolicyRuleProjects.php
··· 10 10 } 11 11 12 12 public function willApplyRules(PhabricatorUser $viewer, array $values) { 13 - $values = array_unique(array_filter($values)); 13 + $values = array_unique(array_filter(array_mergev($values))); 14 14 if (!$values) { 15 15 return; 16 16 }
+46
src/view/form/control/AphrontFormPolicyControl.php
··· 54 54 'icon' => $policy->getIcon(), 55 55 ); 56 56 } 57 + 58 + // If we were passed several custom policy options, throw away the ones 59 + // which aren't the value for this capability. For example, an object might 60 + // have a custom view pollicy and a custom edit policy. When we render 61 + // the selector for "Can View", we don't want to show the "Can Edit" 62 + // custom policy -- if we did, the menu would look like this: 63 + // 64 + // Custom 65 + // Custom Policy 66 + // Custom Policy 67 + // 68 + // ...where one is the "view" custom policy, and one is the "edit" custom 69 + // policy. 70 + 71 + $type_custom = PhabricatorPolicyType::TYPE_CUSTOM; 72 + if (!empty($options[$type_custom])) { 73 + $options[$type_custom] = array_select_keys( 74 + $options[$type_custom], 75 + array($this->getValue())); 76 + } 77 + 78 + // If there aren't any custom policies, add a placeholder policy so we 79 + // render a menu item. This allows the user to switch to a custom policy. 80 + 81 + if (empty($options[$type_custom])) { 82 + $placeholder = new PhabricatorPolicy(); 83 + $placeholder->setName(pht('Custom Policy...')); 84 + $options[$type_custom][$this->getCustomPolicyPlaceholder()] = array( 85 + 'name' => $placeholder->getName(), 86 + 'full' => $placeholder->getName(), 87 + 'icon' => $placeholder->getIcon(), 88 + ); 89 + } 90 + 91 + $options = array_select_keys( 92 + $options, 93 + array( 94 + PhabricatorPolicyType::TYPE_GLOBAL, 95 + PhabricatorPolicyType::TYPE_CUSTOM, 96 + PhabricatorPolicyType::TYPE_PROJECT, 97 + )); 98 + 57 99 return $options; 58 100 } 59 101 ··· 121 163 'icons' => $icons, 122 164 'labels' => $labels, 123 165 'value' => $this->getValue(), 166 + 'customPlaceholder' => $this->getCustomPolicyPlaceholder(), 124 167 )); 125 168 126 169 $selected = $flat_options[$this->getValue()]; ··· 165 208 )); 166 209 } 167 210 211 + private function getCustomPolicyPlaceholder() { 212 + return 'custom:placeholder'; 213 + } 168 214 169 215 }
+76 -11
webroot/rsrc/js/application/policy/behavior-policy-control.js
··· 5 5 * javelin-util 6 6 * phabricator-dropdown-menu 7 7 * phabricator-menu-item 8 + * javelin-workflow 8 9 * @javelin 9 10 */ 10 11 JX.behavior('policy-control', function(config) { ··· 23 24 for (var ii = 0; ii < config.groups.length; ii++) { 24 25 var group = config.groups[ii]; 25 26 26 - var header = new JX.PhabricatorMenuItem(config.labels[group]); 27 + var header = new JX.PhabricatorMenuItem(config.labels[group], JX.bag); 27 28 header.setDisabled(true); 28 29 menu.addItem(header); 29 30 30 31 for (var jj = 0; jj < config.order[group].length; jj++) { 31 32 var phid = config.order[group][jj]; 32 - var option = config.options[phid]; 33 33 34 - var render = [JX.$H(config.icons[option.icon]), option.name]; 34 + var onselect; 35 + if (group == 'custom') { 36 + onselect = JX.bind(null, function(phid) { 37 + var uri = get_custom_uri(phid); 38 + 39 + new JX.Workflow(uri) 40 + .setHandler(function(response) { 41 + if (!response.phid) { 42 + return; 43 + } 44 + 45 + replace_policy(phid, response.phid, response.info); 46 + select_policy(response.phid); 47 + }) 48 + .start(); 49 + 50 + }, phid); 51 + } else { 52 + onselect = JX.bind(null, select_policy, phid); 53 + } 35 54 36 55 var item = new JX.PhabricatorMenuItem( 37 - render, 38 - JX.bind(null, function(phid, render) { 39 - JX.DOM.setContent( 40 - JX.DOM.find(control, 'span', 'policy-label'), 41 - render); 42 - input.value = phid; 43 - value = phid; 44 - }, phid, render)); 56 + render_option(phid, true), 57 + onselect); 45 58 46 59 if (phid == value) { 47 60 item.setSelected(true); ··· 52 65 } 53 66 54 67 }); 68 + 69 + 70 + var select_policy = function(phid) { 71 + JX.DOM.setContent( 72 + JX.DOM.find(control, 'span', 'policy-label'), 73 + render_option(phid)); 74 + 75 + input.value = phid; 76 + value = phid; 77 + }; 78 + 79 + 80 + var render_option = function(phid, with_title) { 81 + var option = config.options[phid]; 82 + 83 + var name = option.name; 84 + if (with_title && (option.full != option.name)) { 85 + name = JX.$N('span', {title: option.full}, name); 86 + } 87 + 88 + return [JX.$H(config.icons[option.icon]), name]; 89 + }; 90 + 91 + 92 + /** 93 + * Get the workflow URI to create or edit a policy with a given PHID. 94 + */ 95 + var get_custom_uri = function(phid) { 96 + var uri = '/policy/edit/'; 97 + if (phid != config.customPlaceholder) { 98 + uri += phid + '/'; 99 + } 100 + return uri; 101 + }; 102 + 103 + 104 + /** 105 + * Replace an existing policy option with a new one. Used to swap out custom 106 + * policies after the user edits them. 107 + */ 108 + var replace_policy = function(old_phid, new_phid, info) { 109 + config.options[new_phid] = info; 110 + for (var k in config.order) { 111 + for (var ii = 0; ii < config.order[k].length; ii++) { 112 + if (config.order[k][ii] == old_phid) { 113 + config.order[k][ii] = new_phid; 114 + return; 115 + } 116 + } 117 + } 118 + }; 119 + 55 120 56 121 });