mirror of
https://we.phorge.it/source/phorge.git
synced 2024-11-23 07:12:41 +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:
parent
3a4c08d7f1
commit
76dfeb95ba
5 changed files with 135 additions and 15 deletions
|
@ -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',
|
||||||
),
|
),
|
||||||
|
|
|
@ -47,9 +47,17 @@ 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.
|
||||||
|
$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;
|
continue;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if ($new == PhabricatorPolicies::POLICY_PUBLIC) {
|
if ($new == PhabricatorPolicies::POLICY_PUBLIC) {
|
||||||
$capobj = PhabricatorPolicyCapability::getCapabilityByKey(
|
$capobj = PhabricatorPolicyCapability::getCapabilityByKey(
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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';
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue