Also fixes an issue where the deleted bit was not removed from permissions when editing was cancelled. Bug: Issue 8035 Change-Id: I333fda2986117a82ed19bc5e55310469b17e451b
		
			
				
	
	
		
			244 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
			
		
		
	
	
			244 lines
		
	
	
		
			6.9 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
// 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;
 | 
						|
 | 
						|
  /**
 | 
						|
   * Fired when the permission has been modified or removed.
 | 
						|
   *
 | 
						|
   * @event access-modified
 | 
						|
   */
 | 
						|
 | 
						|
  Polymer({
 | 
						|
    is: 'gr-permission',
 | 
						|
 | 
						|
    properties: {
 | 
						|
      labels: Object,
 | 
						|
      name: String,
 | 
						|
      /** @type {?} */
 | 
						|
      permission: {
 | 
						|
        type: Object,
 | 
						|
        observer: '_sortPermission',
 | 
						|
        notify: true,
 | 
						|
      },
 | 
						|
      groups: Object,
 | 
						|
      section: String,
 | 
						|
      editing: {
 | 
						|
        type: Boolean,
 | 
						|
        value: false,
 | 
						|
        observer: '_handleEditingChanged',
 | 
						|
      },
 | 
						|
      _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,
 | 
						|
      },
 | 
						|
      _originalExclusiveValue: Boolean,
 | 
						|
    },
 | 
						|
 | 
						|
    behaviors: [
 | 
						|
      Gerrit.AccessBehavior,
 | 
						|
    ],
 | 
						|
 | 
						|
    observers: [
 | 
						|
      '_handleRulesChanged(_rules.splices)',
 | 
						|
    ],
 | 
						|
 | 
						|
    listeners: {
 | 
						|
      'access-saved': '_handleAccessSaved',
 | 
						|
    },
 | 
						|
 | 
						|
    ready() {
 | 
						|
      this._setupValues();
 | 
						|
    },
 | 
						|
 | 
						|
    _setupValues() {
 | 
						|
      if (!this.permission) { return; }
 | 
						|
      this._originalExclusiveValue = !!this.permission.value.exclusive;
 | 
						|
      Polymer.dom.flush();
 | 
						|
    },
 | 
						|
 | 
						|
    _handleAccessSaved() {
 | 
						|
      // Set a new 'original' value to keep track of after the value has been
 | 
						|
      // saved.
 | 
						|
      this._setupValues();
 | 
						|
    },
 | 
						|
 | 
						|
    _permissionIsOwner(permissionId) {
 | 
						|
      return permissionId === 'owner';
 | 
						|
    },
 | 
						|
 | 
						|
    _handleEditingChanged(editing, editingOld) {
 | 
						|
      // Ignore when editing gets set initially.
 | 
						|
      if (!editingOld) { return; }
 | 
						|
      // Restore original values if no longer editing.
 | 
						|
      if (!editing) {
 | 
						|
        this._deleted = false;
 | 
						|
        delete this.permission.value.deleted;
 | 
						|
        this._groupFilter = '';
 | 
						|
        this._rules = this._rules.filter(rule => !rule.value.added);
 | 
						|
 | 
						|
        // Restore exclusive bit to original.
 | 
						|
        this.set(['permission', 'value', 'exclusive'],
 | 
						|
            this._originalExclusiveValue);
 | 
						|
      }
 | 
						|
    },
 | 
						|
 | 
						|
    _handleValueChange() {
 | 
						|
      this.permission.value.modified = true;
 | 
						|
      // Allows overall access page to know a change has been made.
 | 
						|
      this.dispatchEvent(new CustomEvent('access-modified', {bubbles: true}));
 | 
						|
    },
 | 
						|
 | 
						|
    _handleRemovePermission() {
 | 
						|
      this._deleted = true;
 | 
						|
      this.permission.value.deleted = true;
 | 
						|
      this.dispatchEvent(new CustomEvent('access-modified', {bubbles: true}));
 | 
						|
    },
 | 
						|
 | 
						|
    _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);
 | 
						|
    },
 | 
						|
 | 
						|
    _computeSectionClass(editing, deleted) {
 | 
						|
      const classList = [];
 | 
						|
      if (editing) {
 | 
						|
        classList.push('editing');
 | 
						|
      }
 | 
						|
      if (deleted) {
 | 
						|
        classList.push('deleted');
 | 
						|
      }
 | 
						|
      return classList.join(' ');
 | 
						|
    },
 | 
						|
 | 
						|
    _handleUndoRemove() {
 | 
						|
      this._deleted = false;
 | 
						|
      delete this.permission.value.deleted;
 | 
						|
    },
 | 
						|
 | 
						|
    _computeLabel(permission, labels) {
 | 
						|
      if (!permission.value.label) { return; }
 | 
						|
 | 
						|
      const labelName = permission.value.label;
 | 
						|
 | 
						|
      // It is possible to have a label name that is not included in the
 | 
						|
      // 'labels' object. In this case, treat it like anything else.
 | 
						|
      if (!labels[labelName]) { return; }
 | 
						|
      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;
 | 
						|
    },
 | 
						|
 | 
						|
    _computeGroupName(groups, groupId) {
 | 
						|
      return groups && groups[groupId] && groups[groupId].name ?
 | 
						|
          groups[groupId].name : groupId;
 | 
						|
    },
 | 
						|
 | 
						|
    _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) {
 | 
						|
      // The group id is encoded, but have to decode in order for the access
 | 
						|
      // API to work as expected.
 | 
						|
      const groupId = decodeURIComponent(e.detail.value.id);
 | 
						|
      this.set(['permission', 'value', 'rules', groupId], {});
 | 
						|
 | 
						|
      // Purposely don't recompute sorted array so that the newly added rule
 | 
						|
      // is the last item of the array.
 | 
						|
      this.push('_rules', {
 | 
						|
        id: groupId,
 | 
						|
      });
 | 
						|
 | 
						|
      // 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();
 | 
						|
      const value = this._rules[this._rules.length - 1].value;
 | 
						|
      value.added = true;
 | 
						|
      this.set(['permission', 'value', 'rules', groupId], value);
 | 
						|
      this.dispatchEvent(new CustomEvent('access-modified', {bubbles: true}));
 | 
						|
    },
 | 
						|
  });
 | 
						|
})(); |