1
0
Fork 0
mirror of https://we.phorge.it/source/phorge.git synced 2024-11-27 01:02:42 +01:00

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
This commit is contained in:
epriestley 2013-10-14 16:59:16 -07:00
parent 3a4c08d7f1
commit 76dfeb95ba
5 changed files with 135 additions and 15 deletions

View file

@ -2295,7 +2295,7 @@ celerity_register_resource_map(array(
), ),
'javelin-behavior-policy-control' => 'javelin-behavior-policy-control' =>
array( array(
'uri' => '/res/f43ba427/rsrc/js/application/policy/behavior-policy-control.js', 'uri' => '/res/ce9f54c8/rsrc/js/application/policy/behavior-policy-control.js',
'type' => 'js', 'type' => 'js',
'requires' => 'requires' =>
array( array(
@ -2304,6 +2304,7 @@ celerity_register_resource_map(array(
2 => 'javelin-util', 2 => 'javelin-util',
3 => 'phabricator-dropdown-menu', 3 => 'phabricator-dropdown-menu',
4 => 'phabricator-menu-item', 4 => 'phabricator-menu-item',
5 => 'javelin-workflow',
), ),
'disk' => '/rsrc/js/application/policy/behavior-policy-control.js', 'disk' => '/rsrc/js/application/policy/behavior-policy-control.js',
), ),

View file

@ -47,8 +47,16 @@ final class PhabricatorApplicationEditController
} }
if (empty($policies[$new])) { if (empty($policies[$new])) {
// Can't set the policy to something invalid. // Not a standard policy, check for a custom policy.
continue; $policy = id(new PhabricatorPolicyQuery())
->setViewer($user)
->withPHIDs(array($new))
->executeOne();
if (!$policy) {
// Not a custom policy either. Can't set the policy to something
// invalid, so skip this.
continue;
}
} }
if ($new == PhabricatorPolicies::POLICY_PUBLIC) { if ($new == PhabricatorPolicies::POLICY_PUBLIC) {

View file

@ -10,7 +10,7 @@ final class PhabricatorPolicyRuleProjects
} }
public function willApplyRules(PhabricatorUser $viewer, array $values) { public function willApplyRules(PhabricatorUser $viewer, array $values) {
$values = array_unique(array_filter($values)); $values = array_unique(array_filter(array_mergev($values)));
if (!$values) { if (!$values) {
return; return;
} }

View file

@ -54,6 +54,48 @@ final class AphrontFormPolicyControl extends AphrontFormControl {
'icon' => $policy->getIcon(), 'icon' => $policy->getIcon(),
); );
} }
// If we were passed several custom policy options, throw away the ones
// which aren't the value for this capability. For example, an object might
// have a custom view pollicy and a custom edit policy. When we render
// the selector for "Can View", we don't want to show the "Can Edit"
// custom policy -- if we did, the menu would look like this:
//
// Custom
// Custom Policy
// Custom Policy
//
// ...where one is the "view" custom policy, and one is the "edit" custom
// policy.
$type_custom = PhabricatorPolicyType::TYPE_CUSTOM;
if (!empty($options[$type_custom])) {
$options[$type_custom] = array_select_keys(
$options[$type_custom],
array($this->getValue()));
}
// If there aren't any custom policies, add a placeholder policy so we
// render a menu item. This allows the user to switch to a custom policy.
if (empty($options[$type_custom])) {
$placeholder = new PhabricatorPolicy();
$placeholder->setName(pht('Custom Policy...'));
$options[$type_custom][$this->getCustomPolicyPlaceholder()] = array(
'name' => $placeholder->getName(),
'full' => $placeholder->getName(),
'icon' => $placeholder->getIcon(),
);
}
$options = array_select_keys(
$options,
array(
PhabricatorPolicyType::TYPE_GLOBAL,
PhabricatorPolicyType::TYPE_CUSTOM,
PhabricatorPolicyType::TYPE_PROJECT,
));
return $options; return $options;
} }
@ -121,6 +163,7 @@ final class AphrontFormPolicyControl extends AphrontFormControl {
'icons' => $icons, 'icons' => $icons,
'labels' => $labels, 'labels' => $labels,
'value' => $this->getValue(), 'value' => $this->getValue(),
'customPlaceholder' => $this->getCustomPolicyPlaceholder(),
)); ));
$selected = $flat_options[$this->getValue()]; $selected = $flat_options[$this->getValue()];
@ -165,5 +208,8 @@ final class AphrontFormPolicyControl extends AphrontFormControl {
)); ));
} }
private function getCustomPolicyPlaceholder() {
return 'custom:placeholder';
}
} }

View file

@ -5,6 +5,7 @@
* javelin-util * javelin-util
* phabricator-dropdown-menu * phabricator-dropdown-menu
* phabricator-menu-item * phabricator-menu-item
* javelin-workflow
* @javelin * @javelin
*/ */
JX.behavior('policy-control', function(config) { JX.behavior('policy-control', function(config) {
@ -23,25 +24,37 @@ JX.behavior('policy-control', function(config) {
for (var ii = 0; ii < config.groups.length; ii++) { for (var ii = 0; ii < config.groups.length; ii++) {
var group = config.groups[ii]; var group = config.groups[ii];
var header = new JX.PhabricatorMenuItem(config.labels[group]); var header = new JX.PhabricatorMenuItem(config.labels[group], JX.bag);
header.setDisabled(true); header.setDisabled(true);
menu.addItem(header); menu.addItem(header);
for (var jj = 0; jj < config.order[group].length; jj++) { for (var jj = 0; jj < config.order[group].length; jj++) {
var phid = config.order[group][jj]; var phid = config.order[group][jj];
var option = config.options[phid];
var render = [JX.$H(config.icons[option.icon]), option.name]; var onselect;
if (group == 'custom') {
onselect = JX.bind(null, function(phid) {
var uri = get_custom_uri(phid);
new JX.Workflow(uri)
.setHandler(function(response) {
if (!response.phid) {
return;
}
replace_policy(phid, response.phid, response.info);
select_policy(response.phid);
})
.start();
}, phid);
} else {
onselect = JX.bind(null, select_policy, phid);
}
var item = new JX.PhabricatorMenuItem( var item = new JX.PhabricatorMenuItem(
render, render_option(phid, true),
JX.bind(null, function(phid, render) { onselect);
JX.DOM.setContent(
JX.DOM.find(control, 'span', 'policy-label'),
render);
input.value = phid;
value = phid;
}, phid, render));
if (phid == value) { if (phid == value) {
item.setSelected(true); item.setSelected(true);
@ -53,4 +66,56 @@ JX.behavior('policy-control', function(config) {
}); });
var select_policy = function(phid) {
JX.DOM.setContent(
JX.DOM.find(control, 'span', 'policy-label'),
render_option(phid));
input.value = phid;
value = phid;
};
var render_option = function(phid, with_title) {
var option = config.options[phid];
var name = option.name;
if (with_title && (option.full != option.name)) {
name = JX.$N('span', {title: option.full}, name);
}
return [JX.$H(config.icons[option.icon]), name];
};
/**
* Get the workflow URI to create or edit a policy with a given PHID.
*/
var get_custom_uri = function(phid) {
var uri = '/policy/edit/';
if (phid != config.customPlaceholder) {
uri += phid + '/';
}
return uri;
};
/**
* Replace an existing policy option with a new one. Used to swap out custom
* policies after the user edits them.
*/
var replace_policy = function(old_phid, new_phid, info) {
config.options[new_phid] = info;
for (var k in config.order) {
for (var ii = 0; ii < config.order[k].length; ii++) {
if (config.order[k][ii] == old_phid) {
config.order[k][ii] = new_phid;
return;
}
}
}
};
}); });