Introduce gr-permission
This element houses rules for a particular project access section.
Here is the access hierarchy:
Project access
- Sections
- Permissions <-- This is the component for this change
- Rules
It has the ability to add new rules, or remove itself (with an undo
option).
Rules that already exist in a particular permission will not be present
in the autocomplete options.
Change-Id: I4db09d1a8bb7f738dff771867d25fce424a3ea3a
This commit is contained in:
@@ -0,0 +1,151 @@
|
||||
<!--
|
||||
Copyright (C) 2017 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<script>
|
||||
(function(window) {
|
||||
'use strict';
|
||||
|
||||
window.Gerrit = window.Gerrit || {};
|
||||
|
||||
/** @polymerBehavior Gerrit.AccessBehavior */
|
||||
Gerrit.AccessBehavior = {
|
||||
properties: {
|
||||
permissionValues: {
|
||||
type: Object,
|
||||
readOnly: true,
|
||||
value: {
|
||||
abandon: {
|
||||
id: 'abandon',
|
||||
name: 'Abandon',
|
||||
},
|
||||
addPatchSet: {
|
||||
id: 'addPatchSet',
|
||||
name: 'Add Patch Set',
|
||||
},
|
||||
create: {
|
||||
id: 'create',
|
||||
name: 'Create Reference',
|
||||
},
|
||||
createTag: {
|
||||
id: 'createTag',
|
||||
name: 'Create Annotated Tag',
|
||||
},
|
||||
createSignedTag: {
|
||||
id: 'createSignedTag',
|
||||
name: 'Create Signed Tag',
|
||||
},
|
||||
delete: {
|
||||
id: 'delete',
|
||||
name: 'Delete Reference',
|
||||
},
|
||||
deleteDrafts: {
|
||||
id: 'deleteDrafts',
|
||||
name: 'Delete Drafts',
|
||||
},
|
||||
deleteOwnChanges: {
|
||||
id: 'deleteOwnChanges',
|
||||
name: 'Delete Own Changes',
|
||||
},
|
||||
editAssignee: {
|
||||
id: 'editAssignee',
|
||||
name: 'Edit Assignee',
|
||||
},
|
||||
editHashtags: {
|
||||
id: 'editHashtags',
|
||||
name: 'Edit Hashtags',
|
||||
},
|
||||
editTopicName: {
|
||||
id: 'editTopicName',
|
||||
name: 'Edit Topic Name',
|
||||
},
|
||||
forgeAuthor: {
|
||||
id: 'forgeAuthor',
|
||||
name: 'Forge Author Identity',
|
||||
},
|
||||
forgeCommitter: {
|
||||
id: 'forgeCommitter',
|
||||
name: 'Forge Committer Identity',
|
||||
},
|
||||
forgeServerAsCommitter: {
|
||||
id: 'forgeServerAsCommitter',
|
||||
name: 'Forge Server Identity',
|
||||
},
|
||||
owner: {
|
||||
id: 'owner',
|
||||
name: 'Owner',
|
||||
},
|
||||
publishDrafts: {
|
||||
id: 'publishDrafts',
|
||||
name: 'Publish Drafts',
|
||||
},
|
||||
push: {
|
||||
id: 'push',
|
||||
name: 'Push',
|
||||
},
|
||||
pushMerge: {
|
||||
id: 'pushMerge',
|
||||
name: 'Push Merge Commit',
|
||||
},
|
||||
read: {
|
||||
id: 'read',
|
||||
name: 'Read',
|
||||
},
|
||||
rebase: {
|
||||
id: 'rebase',
|
||||
name: 'Rebase',
|
||||
},
|
||||
removeReviewer: {
|
||||
id: 'removeReviewer',
|
||||
name: 'Remove Reviewer',
|
||||
},
|
||||
submit: {
|
||||
id: 'submit',
|
||||
name: 'Submit',
|
||||
},
|
||||
submitAs: {
|
||||
id: 'submitAs',
|
||||
name: 'Submit (On Behalf Of)',
|
||||
},
|
||||
viewDrafts: {
|
||||
id: 'viewDrafts',
|
||||
name: 'View Drafts',
|
||||
},
|
||||
viewPrivateChanges: {
|
||||
id: 'viewPrivateChanges',
|
||||
name: 'View Private Changes',
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {!Object} obj
|
||||
* @return {!Array} returns a sorted array sorted by the id of the original
|
||||
* object.
|
||||
*/
|
||||
toSortedArray(obj) {
|
||||
return Object.keys(obj).map(key => {
|
||||
return {
|
||||
id: key,
|
||||
value: obj[key],
|
||||
};
|
||||
}).sort((a, b) => {
|
||||
return a.id > b.id;
|
||||
});
|
||||
},
|
||||
};
|
||||
})(window);
|
||||
</script>
|
||||
@@ -0,0 +1,68 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
Copyright (C) 2017 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
|
||||
<title>keyboard-shortcut-behavior</title>
|
||||
|
||||
<script src="../../bower_components/webcomponentsjs/webcomponents.min.js"></script>
|
||||
<script src="../../bower_components/web-component-tester/browser.js"></script>
|
||||
<link rel="import" href="../../test/common-test-setup.html"/>
|
||||
<link rel="import" href="gr-access-behavior.html">
|
||||
|
||||
<test-fixture id="basic">
|
||||
<template>
|
||||
<test-element></test-element>
|
||||
</template>
|
||||
</test-fixture>
|
||||
|
||||
<script>
|
||||
suite('gr-access-behavior tests', () => {
|
||||
let element;
|
||||
|
||||
suiteSetup(() => {
|
||||
// Define a Polymer element that uses this behavior.
|
||||
Polymer({
|
||||
is: 'test-element',
|
||||
behaviors: [Gerrit.AccessBehavior],
|
||||
});
|
||||
});
|
||||
|
||||
setup(() => {
|
||||
element = fixture('basic');
|
||||
});
|
||||
|
||||
test('toSortedArray', () => {
|
||||
const rules = {
|
||||
'global:Project-Owners': {
|
||||
action: 'ALLOW', force: false,
|
||||
},
|
||||
'4c97682e6ce6b7247f3381b6f1789356666de7f': {
|
||||
action: 'ALLOW', force: false,
|
||||
},
|
||||
};
|
||||
const expectedResult = [
|
||||
{id: '4c97682e6ce6b7247f3381b6f1789356666de7f', value: {
|
||||
action: 'ALLOW', force: false,
|
||||
}},
|
||||
{id: 'global:Project-Owners', value: {
|
||||
action: 'ALLOW', force: false,
|
||||
}},
|
||||
];
|
||||
assert.deepEqual(element.toSortedArray(rules), expectedResult);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -0,0 +1,107 @@
|
||||
<!--
|
||||
Copyright (C) 2017 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<link rel="import" href="../../../bower_components/polymer/polymer.html">
|
||||
<link rel="import" href="../../../behaviors/gr-access-behavior/gr-access-behavior.html">
|
||||
<link rel="import" href="../../../styles/gr-form-styles.html">
|
||||
<link rel="import" href="../../../styles/gr-menu-page-styles.html">
|
||||
<link rel="import" href="../../../styles/shared-styles.html">
|
||||
<link rel="import" href="../../shared/gr-autocomplete/gr-autocomplete.html">
|
||||
<link rel="import" href="../../shared/gr-button/gr-button.html">
|
||||
<link rel="import" href="../../shared/gr-rest-api-interface/gr-rest-api-interface.html">
|
||||
<link rel="import" href="../gr-rule-editor/gr-rule-editor.html">
|
||||
|
||||
<dom-module id="gr-permission">
|
||||
<template>
|
||||
<style include="shared-styles">
|
||||
:host {
|
||||
display: block;
|
||||
margin-bottom: .7em;
|
||||
}
|
||||
.header {
|
||||
align-items: baseline;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
margin: .3em .7em;
|
||||
}
|
||||
#deletedContainer {
|
||||
border: 1px solid #d1d2d3;
|
||||
padding: .7em;
|
||||
}
|
||||
.rules {
|
||||
background: #fafafa;
|
||||
border: 1px solid #d1d2d3;
|
||||
}
|
||||
.title {
|
||||
margin-bottom: .3em;
|
||||
}
|
||||
#addRule {
|
||||
padding: .7em;
|
||||
}
|
||||
#deletedContainer,
|
||||
.deleted #mainContainer {
|
||||
display: none;
|
||||
}
|
||||
.deleted #deletedContainer,
|
||||
#mainContainer {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
<style include="gr-form-styles"></style>
|
||||
<style include="gr-menu-page-styles"></style>
|
||||
<section
|
||||
id="permission"
|
||||
class$="gr-form-styles [[_computeDeletedClass(_deleted)]]">
|
||||
<div id="mainContainer">
|
||||
<div class="header">
|
||||
<span class="title">[[name]]</span>
|
||||
<gr-button
|
||||
id="removeBtn"
|
||||
on-tap="_handleRemovePermission">Remove</gr-button>
|
||||
</div><!-- end header -->
|
||||
<div class="rules">
|
||||
<template
|
||||
is="dom-repeat"
|
||||
items="{{_rules}}"
|
||||
as="rule">
|
||||
<gr-rule-editor
|
||||
label="[[_label]]"
|
||||
group="[[rule.id]]"
|
||||
permission="[[permission.id]]"
|
||||
rule="{{rule}}"
|
||||
section="[[section]]"></gr-rule-editor>
|
||||
</template>
|
||||
<div id="addRule">
|
||||
<gr-autocomplete
|
||||
text="{{_groupFilter}}"
|
||||
query="[[_query]]"
|
||||
placeholder="Add group"
|
||||
on-commit="_handleAddRuleItem">
|
||||
</gr-autocomplete>
|
||||
</div> <!-- end addRule -->
|
||||
</div> <!-- end rules -->
|
||||
</div><!-- end mainContainer -->
|
||||
<div id="deletedContainer">
|
||||
[[name]] was deleted
|
||||
<gr-button
|
||||
id="undoRemoveBtn"
|
||||
on-tap="_handleUndoRemove">Undo</gr-button>
|
||||
</div><!-- end deletedContainer -->
|
||||
</section>
|
||||
<gr-rest-api-interface id="restAPI"></gr-rest-api-interface>
|
||||
</template>
|
||||
<script src="gr-permission.js"></script>
|
||||
</dom-module>
|
||||
164
polygerrit-ui/app/elements/admin/gr-permission/gr-permission.js
Normal file
164
polygerrit-ui/app/elements/admin/gr-permission/gr-permission.js
Normal file
@@ -0,0 +1,164 @@
|
||||
// Copyright (C) 2017 The Android Open Source Project
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
const MAX_AUTOCOMPLETE_RESULTS = 20;
|
||||
|
||||
Polymer({
|
||||
is: 'gr-permission',
|
||||
|
||||
properties: {
|
||||
labels: Object,
|
||||
name: String,
|
||||
/** @type {?} */
|
||||
permission: {
|
||||
type: Object,
|
||||
observer: '_sortPermission',
|
||||
notify: true,
|
||||
},
|
||||
section: String,
|
||||
|
||||
_label: {
|
||||
type: Object,
|
||||
computed: '_computeLabel(permission, labels)',
|
||||
},
|
||||
_groupFilter: String,
|
||||
_query: {
|
||||
type: Function,
|
||||
value() {
|
||||
return this._getGroupSuggestions.bind(this);
|
||||
},
|
||||
},
|
||||
_rules: Array,
|
||||
_groupsWithRules: Object,
|
||||
_deleted: {
|
||||
type: Boolean,
|
||||
value: false,
|
||||
},
|
||||
},
|
||||
|
||||
behaviors: [
|
||||
Gerrit.AccessBehavior,
|
||||
],
|
||||
|
||||
observers: [
|
||||
'_handleRulesChanged(_rules.splices)',
|
||||
],
|
||||
|
||||
_handleRulesChanged(changeRecord) {
|
||||
// Update the groups to exclude in the autocomplete.
|
||||
this._groupsWithRules = this._computeGroupsWithRules(this._rules);
|
||||
},
|
||||
|
||||
_sortPermission(permission) {
|
||||
this._rules = this.toSortedArray(permission.value.rules);
|
||||
},
|
||||
|
||||
_handleRemovePermission() {
|
||||
this._deleted = true;
|
||||
this.set('permission.value.deleted', true);
|
||||
},
|
||||
|
||||
_computeDeletedClass(deleted) {
|
||||
return deleted ? 'deleted' : '';
|
||||
},
|
||||
|
||||
_handleUndoRemove() {
|
||||
this._deleted = false;
|
||||
delete this.permission.value.deleted;
|
||||
},
|
||||
|
||||
_computeLabel(permission, labels) {
|
||||
if (!permission.value.label) { return; }
|
||||
|
||||
const labelName = permission.value.label;
|
||||
const label = {
|
||||
name: labelName,
|
||||
values: this._computeLabelValues(labels[labelName].values),
|
||||
};
|
||||
return label;
|
||||
},
|
||||
|
||||
_computeLabelValues(values) {
|
||||
const valuesArr = [];
|
||||
const keys = Object.keys(values).sort((a, b) => {
|
||||
return parseInt(a, 10) - parseInt(b, 10);
|
||||
});
|
||||
|
||||
for (const key of keys) {
|
||||
if (!values[key]) { return; }
|
||||
// The value from the server being used to choose which item is
|
||||
// selected is in integer form, so this must be converted.
|
||||
valuesArr.push({value: parseInt(key, 10), text: values[key]});
|
||||
}
|
||||
return valuesArr;
|
||||
},
|
||||
|
||||
/**
|
||||
* @param {!Array} rules
|
||||
* @return {!Object} Object with groups with rues as keys, and true as
|
||||
* value.
|
||||
*/
|
||||
_computeGroupsWithRules(rules) {
|
||||
const groups = {};
|
||||
for (const rule of rules) {
|
||||
groups[rule.id] = true;
|
||||
}
|
||||
return groups;
|
||||
},
|
||||
|
||||
_getGroupSuggestions() {
|
||||
return this.$.restAPI.getSuggestedGroups(
|
||||
this._groupFilter,
|
||||
MAX_AUTOCOMPLETE_RESULTS)
|
||||
.then(response => {
|
||||
const groups = [];
|
||||
for (const key in response) {
|
||||
if (!response.hasOwnProperty(key)) { continue; }
|
||||
groups.push({
|
||||
name: key,
|
||||
value: response[key],
|
||||
});
|
||||
}
|
||||
// Does not return groups in which we already have rules for.
|
||||
return groups.filter(group => {
|
||||
return !this._groupsWithRules[group.value.id];
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* Handles adding a skeleton item to the dom-repeat.
|
||||
* gr-rule-editor handles setting the default values.
|
||||
*/
|
||||
_handleAddRuleItem(e) {
|
||||
this.set(['permission', 'value', 'rules', e.detail.value.id], {});
|
||||
|
||||
// Purposely don't recompute sorted array so that the newly added rule
|
||||
// is the last item of the array.
|
||||
this.push('_rules', {
|
||||
id: e.detail.value.id,
|
||||
});
|
||||
|
||||
// Wait for new rule to get value populated via gr-rule editor, and then
|
||||
// add to permission values as well, so that the change gets propogated
|
||||
// back to the section. Since the rule is inside a dom-repeat, a flush
|
||||
// is needed.
|
||||
Polymer.dom.flush();
|
||||
this.set(['permission', 'value', 'rules', e.detail.value.id],
|
||||
this._rules[this._rules.length - 1].value);
|
||||
},
|
||||
});
|
||||
})();
|
||||
@@ -0,0 +1,293 @@
|
||||
<!DOCTYPE html>
|
||||
<!--
|
||||
Copyright (C) 2017 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<meta name="viewport" content="width=device-width, minimum-scale=1.0, initial-scale=1.0, user-scalable=yes">
|
||||
<title>gr-permission</title>
|
||||
|
||||
<script src="../../../bower_components/page/page.js"></script>
|
||||
<script src="../../../bower_components/webcomponentsjs/webcomponents-lite.min.js"></script>
|
||||
<script src="../../../bower_components/web-component-tester/browser.js"></script>
|
||||
<link rel="import" href="../../../test/common-test-setup.html"/>
|
||||
<link rel="import" href="gr-permission.html">
|
||||
|
||||
<script>void(0);</script>
|
||||
|
||||
<test-fixture id="basic">
|
||||
<template>
|
||||
<gr-permission></gr-permission>
|
||||
</template>
|
||||
</test-fixture>
|
||||
|
||||
<script>
|
||||
suite('gr-permission tests', () => {
|
||||
let element;
|
||||
let sandbox;
|
||||
|
||||
setup(() => {
|
||||
sandbox = sinon.sandbox.create();
|
||||
element = fixture('basic');
|
||||
sandbox.stub(element.$.restAPI, 'getSuggestedGroups').returns(
|
||||
Promise.resolve({
|
||||
'Administrators': {
|
||||
id: '4c97682e6ce61b7247f3381b6f1789356666de7f',
|
||||
},
|
||||
'Anonymous Users': {
|
||||
id: 'global%3AAnonymous-Users',
|
||||
},
|
||||
}));
|
||||
});
|
||||
|
||||
teardown(() => {
|
||||
sandbox.restore();
|
||||
});
|
||||
|
||||
suite('unit tests', () => {
|
||||
test('_sortPermission', () => {
|
||||
const permission = {
|
||||
id: 'submit',
|
||||
value: {
|
||||
rules: {
|
||||
'global:Project-Owners': {
|
||||
action: 'ALLOW',
|
||||
force: false,
|
||||
},
|
||||
'4c97682e6ce6b7247f3381b6f1789356666de7f': {
|
||||
action: 'ALLOW',
|
||||
force: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const expectedRules = [
|
||||
{
|
||||
id: '4c97682e6ce6b7247f3381b6f1789356666de7f',
|
||||
value: {action: 'ALLOW', force: false},
|
||||
},
|
||||
{
|
||||
id: 'global:Project-Owners',
|
||||
value: {action: 'ALLOW', force: false},
|
||||
},
|
||||
];
|
||||
|
||||
element._sortPermission(permission);
|
||||
assert.deepEqual(element._rules, expectedRules);
|
||||
});
|
||||
|
||||
test('_computeLabel and _computeLabelValues', () => {
|
||||
const labels = {
|
||||
'Code-Review': {
|
||||
default_value: 0,
|
||||
values: {
|
||||
' 0': 'No score',
|
||||
'-1': 'I would prefer this is not merged as is',
|
||||
'-2': 'This shall not be merged',
|
||||
'+1': 'Looks good to me, but someone else must approve',
|
||||
'+2': 'Looks good to me, approved',
|
||||
},
|
||||
},
|
||||
};
|
||||
const permission = {
|
||||
id: 'label-Code-Review',
|
||||
value: {
|
||||
label: 'Code-Review',
|
||||
rules: {
|
||||
'global:Project-Owners': {
|
||||
action: 'ALLOW',
|
||||
force: false,
|
||||
min: -2,
|
||||
max: 2,
|
||||
},
|
||||
'4c97682e6ce6b7247f3381b6f1789356666de7f': {
|
||||
action: 'ALLOW',
|
||||
force: false,
|
||||
min: -2,
|
||||
max: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
const expectedLabelValues = [
|
||||
{value: -2, text: 'This shall not be merged'},
|
||||
{value: -1, text: 'I would prefer this is not merged as is'},
|
||||
{value: 0, text: 'No score'},
|
||||
{value: 1, text: 'Looks good to me, but someone else must approve'},
|
||||
{value: 2, text: 'Looks good to me, approved'},
|
||||
];
|
||||
|
||||
const expectedLabel = {
|
||||
name: 'Code-Review',
|
||||
values: expectedLabelValues,
|
||||
};
|
||||
|
||||
assert.deepEqual(element._computeLabelValues(
|
||||
labels['Code-Review'].values), expectedLabelValues);
|
||||
|
||||
assert.deepEqual(element._computeLabel(permission, labels),
|
||||
expectedLabel);
|
||||
});
|
||||
|
||||
test('_computeDeletedClass', () => {
|
||||
let deleted = true;
|
||||
assert.equal(element._computeDeletedClass(deleted), 'deleted');
|
||||
deleted = false;
|
||||
assert.equal(element._computeDeletedClass(deleted), '');
|
||||
});
|
||||
|
||||
test('_computeGroupsWithRules', () => {
|
||||
const rules = [
|
||||
{
|
||||
id: '4c97682e6ce6b7247f3381b6f1789356666de7f',
|
||||
value: {action: 'ALLOW', force: false},
|
||||
},
|
||||
{
|
||||
id: 'global:Project-Owners',
|
||||
value: {action: 'ALLOW', force: false},
|
||||
},
|
||||
];
|
||||
const groupsWithRules = {
|
||||
'4c97682e6ce6b7247f3381b6f1789356666de7f': true,
|
||||
'global:Project-Owners': true,
|
||||
};
|
||||
assert.deepEqual(element._computeGroupsWithRules(rules),
|
||||
groupsWithRules);
|
||||
});
|
||||
|
||||
test('_getGroupSuggestions without existing rules', done => {
|
||||
element._groupsWithRules = {};
|
||||
|
||||
element._getGroupSuggestions().then(groups => {
|
||||
assert.deepEqual(groups, [
|
||||
{
|
||||
name: 'Administrators',
|
||||
value: {id: '4c97682e6ce61b7247f3381b6f1789356666de7f'},
|
||||
}, {
|
||||
name: 'Anonymous Users',
|
||||
value: {id: 'global%3AAnonymous-Users'},
|
||||
},
|
||||
]);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('_getGroupSuggestions with existing rules filters them', done => {
|
||||
element._groupsWithRules = {
|
||||
'4c97682e6ce61b7247f3381b6f1789356666de7f': true,
|
||||
};
|
||||
|
||||
element._getGroupSuggestions().then(groups => {
|
||||
assert.deepEqual(groups, [{
|
||||
name: 'Anonymous Users',
|
||||
value: {id: 'global%3AAnonymous-Users'},
|
||||
}]);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
test('_handleRemovePermission', () => {
|
||||
element.permission = {value: {rules: {}}};
|
||||
element._handleRemovePermission();
|
||||
assert.isTrue(element._deleted);
|
||||
assert.isTrue(element.permission.value.deleted);
|
||||
});
|
||||
|
||||
test('_handleUndoRemove', () => {
|
||||
element.permission = {value: {deleted: true, rules: {}}};
|
||||
element._handleUndoRemove();
|
||||
assert.isFalse(element._deleted);
|
||||
assert.isNotOk(element.permission.value.deleted);
|
||||
});
|
||||
});
|
||||
|
||||
suite('interactions', () => {
|
||||
setup(() => {
|
||||
sandbox.spy(element, '_computeLabel');
|
||||
element.name = 'Priority';
|
||||
element.section = 'refs/*';
|
||||
element.labels = {
|
||||
'Code-Review': {
|
||||
values: {
|
||||
' 0': 'No score',
|
||||
'-1': 'I would prefer this is not merged as is',
|
||||
'-2': 'This shall not be merged',
|
||||
'+1': 'Looks good to me, but someone else must approve',
|
||||
'+2': 'Looks good to me, approved',
|
||||
},
|
||||
default_value: 0,
|
||||
},
|
||||
};
|
||||
element.permission = {
|
||||
id: 'label-Code-Review',
|
||||
value: {
|
||||
label: 'Code-Review',
|
||||
rules: {
|
||||
'global:Project-Owners': {
|
||||
action: 'ALLOW',
|
||||
force: false,
|
||||
min: -2,
|
||||
max: 2,
|
||||
},
|
||||
'4c97682e6ce6b7247f3381b6f1789356666de7f': {
|
||||
action: 'ALLOW',
|
||||
force: false,
|
||||
min: -2,
|
||||
max: 2,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
flushAsynchronousOperations();
|
||||
});
|
||||
|
||||
test('adding a rule', () => {
|
||||
element.name = 'Priority';
|
||||
element.section = 'refs/*';
|
||||
const e = {
|
||||
detail: {
|
||||
value: {
|
||||
id: 'newUserGroupId',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
assert.equal(element._rules.length, 2);
|
||||
assert.equal(Object.keys(element._groupsWithRules).length, 2);
|
||||
element._handleAddRuleItem(e);
|
||||
flushAsynchronousOperations();
|
||||
assert.equal(element._rules.length, 3);
|
||||
assert.equal(Object.keys(element._groupsWithRules).length, 3);
|
||||
assert.deepEqual(element.permission.value.rules['newUserGroupId'],
|
||||
{action: 'ALLOW', min: -2, max: 2});
|
||||
});
|
||||
|
||||
test('removing the permission', () => {
|
||||
element.name = 'Priority';
|
||||
element.section = 'refs/*';
|
||||
|
||||
assert.isFalse(element.$.permission.classList.contains('deleted'));
|
||||
assert.isFalse(element._deleted);
|
||||
MockInteractions.tap(element.$.removeBtn);
|
||||
assert.isTrue(element.$.permission.classList.contains('deleted'));
|
||||
assert.isTrue(element._deleted);
|
||||
MockInteractions.tap(element.$.undoRemoveBtn);
|
||||
assert.isFalse(element.$.permission.classList.contains('deleted'));
|
||||
assert.isFalse(element._deleted);
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
@@ -16,6 +16,7 @@ limitations under the License.
|
||||
|
||||
<link rel="import" href="../../../bower_components/polymer/polymer.html">
|
||||
|
||||
<link rel="import" href="../../../behaviors/gr-access-behavior/gr-access-behavior.html">
|
||||
<link rel="import" href="../../../styles/gr-form-styles.html">
|
||||
<link rel="import" href="../../../styles/shared-styles.html">
|
||||
<link rel="import" href="../../shared/gr-button/gr-button.html">
|
||||
|
||||
@@ -72,6 +72,10 @@
|
||||
},
|
||||
},
|
||||
|
||||
behaviors: [
|
||||
Gerrit.AccessBehavior,
|
||||
],
|
||||
|
||||
observers: [
|
||||
'_handleValueChange(rule.value.*)',
|
||||
],
|
||||
@@ -91,7 +95,8 @@
|
||||
},
|
||||
|
||||
_computeForce(permission) {
|
||||
return 'push' === permission || 'editTopicName' === permission;
|
||||
return this.permissionValues.push.id === permission ||
|
||||
this.permissionValues.editTopicName.id === permission;
|
||||
},
|
||||
|
||||
_computeForceClass(permission) {
|
||||
@@ -103,9 +108,9 @@
|
||||
},
|
||||
|
||||
_computeForceOptions(permission) {
|
||||
if (permission === 'push') {
|
||||
if (permission === this.permissionValues.push.id) {
|
||||
return FORCE_PUSH_OPTIONS;
|
||||
} else if (permission === 'editTopicName') {
|
||||
} else if (permission === this.permissionValues.editTopicName.id) {
|
||||
return FORCE_EDIT_OPTIONS;
|
||||
}
|
||||
return [];
|
||||
@@ -140,12 +145,12 @@
|
||||
|
||||
_handleRemoveRule() {
|
||||
this._deleted = true;
|
||||
this.rule.deleted = true;
|
||||
this.set('rule.value.deleted', true);
|
||||
},
|
||||
|
||||
_handleUndoRemove() {
|
||||
this._deleted = false;
|
||||
delete this.rule.deleted;
|
||||
delete this.rule.value.deleted;
|
||||
},
|
||||
|
||||
_handleUndoChange() {
|
||||
|
||||
@@ -207,15 +207,15 @@ limitations under the License.
|
||||
});
|
||||
|
||||
test('remove rule and undo remove', () => {
|
||||
element.rule = {id: 123};
|
||||
element.rule = {id: 123, value: {action: 'ALLOW'}};
|
||||
assert.isFalse(
|
||||
element.$.deletedContainer.classList.contains('deleted'));
|
||||
MockInteractions.tap(element.$.removeBtn);
|
||||
assert.isTrue(element.$.deletedContainer.classList.contains('deleted'));
|
||||
assert.isTrue(element.rule.deleted);
|
||||
assert.isTrue(element.rule.value.deleted);
|
||||
|
||||
MockInteractions.tap(element.$.undoRemoveBtn);
|
||||
assert.isNotOk(element.rule.deleted);
|
||||
assert.isNotOk(element.rule.value.deleted);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -58,6 +58,5 @@
|
||||
// Character is an ellipsis.
|
||||
return '\u2026/' + pathPieces[pathPieces.length - 1];
|
||||
};
|
||||
|
||||
window.util = util;
|
||||
})(window);
|
||||
|
||||
@@ -40,6 +40,7 @@ limitations under the License.
|
||||
'admin/gr-group/gr-group_test.html',
|
||||
'admin/gr-group-audit-log/gr-group-audit-log_test.html',
|
||||
'admin/gr-group-members/gr-group-members_test.html',
|
||||
'admin/gr-permission/gr-permission_test.html',
|
||||
'admin/gr-plugin-list/gr-plugin-list_test.html',
|
||||
'admin/gr-project/gr-project_test.html',
|
||||
'admin/gr-project-detail-list/gr-project-detail-list_test.html',
|
||||
@@ -152,6 +153,7 @@ limitations under the License.
|
||||
'docs-url-behavior/docs-url-behavior_test.html',
|
||||
'keyboard-shortcut-behavior/keyboard-shortcut-behavior_test.html',
|
||||
'rest-client-behavior/rest-client-behavior_test.html',
|
||||
'gr-access-behavior/gr-access-behavior_test.html',
|
||||
'gr-anonymous-name-behavior/gr-anonymous-name-behavior_test.html',
|
||||
'gr-change-table-behavior/gr-change-table-behavior_test.html',
|
||||
'gr-patch-set-behavior/gr-patch-set-behavior_test.html',
|
||||
|
||||
Reference in New Issue
Block a user