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="../../../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-form-styles.html">
|
||||||
<link rel="import" href="../../../styles/shared-styles.html">
|
<link rel="import" href="../../../styles/shared-styles.html">
|
||||||
<link rel="import" href="../../shared/gr-button/gr-button.html">
|
<link rel="import" href="../../shared/gr-button/gr-button.html">
|
||||||
|
|||||||
@@ -72,6 +72,10 @@
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
behaviors: [
|
||||||
|
Gerrit.AccessBehavior,
|
||||||
|
],
|
||||||
|
|
||||||
observers: [
|
observers: [
|
||||||
'_handleValueChange(rule.value.*)',
|
'_handleValueChange(rule.value.*)',
|
||||||
],
|
],
|
||||||
@@ -91,7 +95,8 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
_computeForce(permission) {
|
_computeForce(permission) {
|
||||||
return 'push' === permission || 'editTopicName' === permission;
|
return this.permissionValues.push.id === permission ||
|
||||||
|
this.permissionValues.editTopicName.id === permission;
|
||||||
},
|
},
|
||||||
|
|
||||||
_computeForceClass(permission) {
|
_computeForceClass(permission) {
|
||||||
@@ -103,9 +108,9 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
_computeForceOptions(permission) {
|
_computeForceOptions(permission) {
|
||||||
if (permission === 'push') {
|
if (permission === this.permissionValues.push.id) {
|
||||||
return FORCE_PUSH_OPTIONS;
|
return FORCE_PUSH_OPTIONS;
|
||||||
} else if (permission === 'editTopicName') {
|
} else if (permission === this.permissionValues.editTopicName.id) {
|
||||||
return FORCE_EDIT_OPTIONS;
|
return FORCE_EDIT_OPTIONS;
|
||||||
}
|
}
|
||||||
return [];
|
return [];
|
||||||
@@ -140,12 +145,12 @@
|
|||||||
|
|
||||||
_handleRemoveRule() {
|
_handleRemoveRule() {
|
||||||
this._deleted = true;
|
this._deleted = true;
|
||||||
this.rule.deleted = true;
|
this.set('rule.value.deleted', true);
|
||||||
},
|
},
|
||||||
|
|
||||||
_handleUndoRemove() {
|
_handleUndoRemove() {
|
||||||
this._deleted = false;
|
this._deleted = false;
|
||||||
delete this.rule.deleted;
|
delete this.rule.value.deleted;
|
||||||
},
|
},
|
||||||
|
|
||||||
_handleUndoChange() {
|
_handleUndoChange() {
|
||||||
|
|||||||
@@ -207,15 +207,15 @@ limitations under the License.
|
|||||||
});
|
});
|
||||||
|
|
||||||
test('remove rule and undo remove', () => {
|
test('remove rule and undo remove', () => {
|
||||||
element.rule = {id: 123};
|
element.rule = {id: 123, value: {action: 'ALLOW'}};
|
||||||
assert.isFalse(
|
assert.isFalse(
|
||||||
element.$.deletedContainer.classList.contains('deleted'));
|
element.$.deletedContainer.classList.contains('deleted'));
|
||||||
MockInteractions.tap(element.$.removeBtn);
|
MockInteractions.tap(element.$.removeBtn);
|
||||||
assert.isTrue(element.$.deletedContainer.classList.contains('deleted'));
|
assert.isTrue(element.$.deletedContainer.classList.contains('deleted'));
|
||||||
assert.isTrue(element.rule.deleted);
|
assert.isTrue(element.rule.value.deleted);
|
||||||
|
|
||||||
MockInteractions.tap(element.$.undoRemoveBtn);
|
MockInteractions.tap(element.$.undoRemoveBtn);
|
||||||
assert.isNotOk(element.rule.deleted);
|
assert.isNotOk(element.rule.value.deleted);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -58,6 +58,5 @@
|
|||||||
// Character is an ellipsis.
|
// Character is an ellipsis.
|
||||||
return '\u2026/' + pathPieces[pathPieces.length - 1];
|
return '\u2026/' + pathPieces[pathPieces.length - 1];
|
||||||
};
|
};
|
||||||
|
|
||||||
window.util = util;
|
window.util = util;
|
||||||
})(window);
|
})(window);
|
||||||
|
|||||||
@@ -40,6 +40,7 @@ limitations under the License.
|
|||||||
'admin/gr-group/gr-group_test.html',
|
'admin/gr-group/gr-group_test.html',
|
||||||
'admin/gr-group-audit-log/gr-group-audit-log_test.html',
|
'admin/gr-group-audit-log/gr-group-audit-log_test.html',
|
||||||
'admin/gr-group-members/gr-group-members_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-plugin-list/gr-plugin-list_test.html',
|
||||||
'admin/gr-project/gr-project_test.html',
|
'admin/gr-project/gr-project_test.html',
|
||||||
'admin/gr-project-detail-list/gr-project-detail-list_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',
|
'docs-url-behavior/docs-url-behavior_test.html',
|
||||||
'keyboard-shortcut-behavior/keyboard-shortcut-behavior_test.html',
|
'keyboard-shortcut-behavior/keyboard-shortcut-behavior_test.html',
|
||||||
'rest-client-behavior/rest-client-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-anonymous-name-behavior/gr-anonymous-name-behavior_test.html',
|
||||||
'gr-change-table-behavior/gr-change-table-behavior_test.html',
|
'gr-change-table-behavior/gr-change-table-behavior_test.html',
|
||||||
'gr-patch-set-behavior/gr-patch-set-behavior_test.html',
|
'gr-patch-set-behavior/gr-patch-set-behavior_test.html',
|
||||||
|
|||||||
Reference in New Issue
Block a user