| /** |
| * @license |
| * 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. |
| */ |
| import '../../../scripts/bundled-polymer.js'; |
| |
| import '@polymer/iron-autogrow-textarea/iron-autogrow-textarea.js'; |
| import '../../../styles/gr-form-styles.js'; |
| import '../../../styles/shared-styles.js'; |
| import '../../shared/gr-button/gr-button.js'; |
| import '../../shared/gr-select/gr-select.js'; |
| import '../../shared/gr-rest-api-interface/gr-rest-api-interface.js'; |
| import {mixinBehaviors} from '@polymer/polymer/lib/legacy/class.js'; |
| import {GestureEventListeners} from '@polymer/polymer/lib/mixins/gesture-event-listeners.js'; |
| import {LegacyElementMixin} from '@polymer/polymer/lib/legacy/legacy-element-mixin.js'; |
| import {PolymerElement} from '@polymer/polymer/polymer-element.js'; |
| import {htmlTemplate} from './gr-rule-editor_html.js'; |
| import {BaseUrlBehavior} from '../../../behaviors/base-url-behavior/base-url-behavior.js'; |
| import {AccessBehavior} from '../../../behaviors/gr-access-behavior/gr-access-behavior.js'; |
| import {URLEncodingBehavior} from '../../../behaviors/gr-url-encoding-behavior/gr-url-encoding-behavior.js'; |
| |
| /** |
| * Fired when the rule has been modified or removed. |
| * |
| * @event access-modified |
| */ |
| |
| /** |
| * Fired when a rule that was previously added was removed. |
| * |
| * @event added-rule-removed |
| */ |
| |
| const PRIORITY_OPTIONS = [ |
| 'BATCH', |
| 'INTERACTIVE', |
| ]; |
| |
| const Action = { |
| ALLOW: 'ALLOW', |
| DENY: 'DENY', |
| BLOCK: 'BLOCK', |
| }; |
| |
| const DROPDOWN_OPTIONS = [Action.ALLOW, Action.DENY, Action.BLOCK]; |
| |
| const ForcePushOptions = { |
| ALLOW: [ |
| {name: 'Allow pushing (but not force pushing)', value: false}, |
| {name: 'Allow pushing with or without force', value: true}, |
| ], |
| BLOCK: [ |
| {name: 'Block pushing with or without force', value: false}, |
| {name: 'Block force pushing', value: true}, |
| ], |
| }; |
| |
| const FORCE_EDIT_OPTIONS = [ |
| { |
| name: 'No Force Edit', |
| value: false, |
| }, |
| { |
| name: 'Force Edit', |
| value: true, |
| }, |
| ]; |
| |
| /** |
| * @extends Polymer.Element |
| */ |
| class GrRuleEditor extends mixinBehaviors( [ |
| AccessBehavior, |
| BaseUrlBehavior, |
| URLEncodingBehavior, |
| ], GestureEventListeners( |
| LegacyElementMixin( |
| PolymerElement))) { |
| static get template() { return htmlTemplate; } |
| |
| static get is() { return 'gr-rule-editor'; } |
| |
| static get properties() { |
| return { |
| hasRange: Boolean, |
| /** @type {?} */ |
| label: Object, |
| editing: { |
| type: Boolean, |
| value: false, |
| observer: '_handleEditingChanged', |
| }, |
| groupId: String, |
| groupName: String, |
| permission: String, |
| /** @type {?} */ |
| rule: { |
| type: Object, |
| notify: true, |
| }, |
| section: String, |
| |
| _deleted: { |
| type: Boolean, |
| value: false, |
| }, |
| _originalRuleValues: Object, |
| }; |
| } |
| |
| static get observers() { |
| return [ |
| '_handleValueChange(rule.value.*)', |
| ]; |
| } |
| |
| /** @override */ |
| created() { |
| super.created(); |
| this.addEventListener('access-saved', |
| () => this._handleAccessSaved()); |
| } |
| |
| /** @override */ |
| ready() { |
| super.ready(); |
| // Called on ready rather than the observer because when new rules are |
| // added, the observer is triggered prior to being ready. |
| if (!this.rule) { return; } // Check needed for test purposes. |
| this._setupValues(this.rule); |
| } |
| |
| /** @override */ |
| attached() { |
| super.attached(); |
| if (!this.rule) { return; } // Check needed for test purposes. |
| if (!this._originalRuleValues) { |
| // Observer _handleValueChange is called after the ready() |
| // method finishes. Original values must be set later to |
| // avoid set .modified flag to true |
| this._setOriginalRuleValues(this.rule.value); |
| } |
| } |
| |
| _setupValues(rule) { |
| if (!rule.value) { |
| this._setDefaultRuleValues(); |
| } |
| } |
| |
| _computeForce(permission, action) { |
| if (this.permissionValues.push.id === permission && |
| action !== Action.DENY) { |
| return true; |
| } |
| |
| return this.permissionValues.editTopicName.id === permission; |
| } |
| |
| _computeForceClass(permission, action) { |
| return this._computeForce(permission, action) ? 'force' : ''; |
| } |
| |
| _computeGroupPath(group) { |
| return `${this.getBaseUrl()}/admin/groups/${this.encodeURL(group, true)}`; |
| } |
| |
| _handleAccessSaved() { |
| // Set a new 'original' value to keep track of after the value has been |
| // saved. |
| this._setOriginalRuleValues(this.rule.value); |
| } |
| |
| _handleEditingChanged(editing, editingOld) { |
| // Ignore when editing gets set initially. |
| if (!editingOld) { return; } |
| // Restore original values if no longer editing. |
| if (!editing) { |
| this._handleUndoChange(); |
| } |
| } |
| |
| _computeSectionClass(editing, deleted) { |
| const classList = []; |
| if (editing) { |
| classList.push('editing'); |
| } |
| if (deleted) { |
| classList.push('deleted'); |
| } |
| return classList.join(' '); |
| } |
| |
| _computeForceOptions(permission, action) { |
| if (permission === this.permissionValues.push.id) { |
| if (action === Action.ALLOW) { |
| return ForcePushOptions.ALLOW; |
| } else if (action === Action.BLOCK) { |
| return ForcePushOptions.BLOCK; |
| } else { |
| return []; |
| } |
| } else if (permission === this.permissionValues.editTopicName.id) { |
| return FORCE_EDIT_OPTIONS; |
| } |
| return []; |
| } |
| |
| _getDefaultRuleValues(permission, label) { |
| const ruleAction = Action.ALLOW; |
| const value = {}; |
| if (permission === 'priority') { |
| value.action = PRIORITY_OPTIONS[0]; |
| return value; |
| } else if (label) { |
| value.min = label.values[0].value; |
| value.max = label.values[label.values.length - 1].value; |
| } else if (this._computeForce(permission, ruleAction)) { |
| value.force = |
| this._computeForceOptions(permission, ruleAction)[0].value; |
| } |
| value.action = DROPDOWN_OPTIONS[0]; |
| return value; |
| } |
| |
| _setDefaultRuleValues() { |
| this.set('rule.value', this._getDefaultRuleValues(this.permission, |
| this.label)); |
| } |
| |
| _computeOptions(permission) { |
| if (permission === 'priority') { |
| return PRIORITY_OPTIONS; |
| } |
| return DROPDOWN_OPTIONS; |
| } |
| |
| _handleRemoveRule() { |
| if (this.rule.value.added) { |
| this.dispatchEvent(new CustomEvent( |
| 'added-rule-removed', {bubbles: true, composed: true})); |
| } |
| this._deleted = true; |
| this.rule.value.deleted = true; |
| this.dispatchEvent( |
| new CustomEvent('access-modified', {bubbles: true, composed: true})); |
| } |
| |
| _handleUndoRemove() { |
| this._deleted = false; |
| delete this.rule.value.deleted; |
| } |
| |
| _handleUndoChange() { |
| // gr-permission will take care of removing rules that were added but |
| // unsaved. We need to keep the added bit for the filter. |
| if (this.rule.value.added) { return; } |
| this.set('rule.value', Object.assign({}, this._originalRuleValues)); |
| this._deleted = false; |
| delete this.rule.value.deleted; |
| delete this.rule.value.modified; |
| } |
| |
| _handleValueChange() { |
| if (!this._originalRuleValues) { return; } |
| this.rule.value.modified = true; |
| // Allows overall access page to know a change has been made. |
| this.dispatchEvent( |
| new CustomEvent('access-modified', {bubbles: true, composed: true})); |
| } |
| |
| _setOriginalRuleValues(value) { |
| this._originalRuleValues = Object.assign({}, value); |
| } |
| } |
| |
| customElements.define(GrRuleEditor.is, GrRuleEditor); |