Add ability to add rule to permission

Change-Id: I004e08a336352892d006d4589f6ca18e22964660
diff --git a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.html b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.html
index 24e8af1..98a1a61 100644
--- a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.html
+++ b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.html
@@ -42,10 +42,9 @@
         border: 1px solid #d1d2d3;
         border-bottom: 0;
       }
-      /* TODO @beckysiegel add back */
-      /* .editing .rules {
+      .editing .rules {
         border-bottom: 1px solid #d1d2d3;
-      } */
+      }
       .title {
         margin-bottom: .3em;
       }
@@ -56,11 +55,10 @@
       .editing #removeBtn {
         display: block;
       }
-      /* TODO @beckysiegel add back */
-      /* .editing #addRule {
+      .editing #addRule {
         display: block;
         padding: .7em;
-      } */
+      }
       #deletedContainer,
       .deleted #mainContainer {
         display: none;
diff --git a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.js b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.js
index 6d44f28..8a0403d 100644
--- a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.js
+++ b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission.js
@@ -74,6 +74,8 @@
       // Restore original values if no longer editing.
       if (!editing) {
         this._deleted = false;
+        this._groupFilter = '';
+        this._rules = this._rules.filter(rule => !rule.value.added);
       }
     },
 
@@ -181,21 +183,26 @@
      * gr-rule-editor handles setting the default values.
      */
     _handleAddRuleItem(e) {
-      this.set(['permission', 'value', 'rules', e.detail.value.id], {});
+      // 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: e.detail.value.id,
+        id: groupId,
       });
 
-      // Wait for new rule to get value populated via gr-rule editor, and then
+      // 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);
+      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}));
     },
   });
 })();
\ No newline at end of file
diff --git a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission_test.html b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission_test.html
index 179d221..88a7472 100644
--- a/polygerrit-ui/app/elements/admin/gr-permission/gr-permission_test.html
+++ b/polygerrit-ui/app/elements/admin/gr-permission/gr-permission_test.html
@@ -309,7 +309,7 @@
         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});
+            {action: 'ALLOW', min: -2, max: 2, added: true});
       });
 
       test('removing the permission', () => {
diff --git a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.js b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.js
index 53c4e39..d903404 100644
--- a/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.js
+++ b/polygerrit-ui/app/elements/admin/gr-repo-access/gr-repo-access.js
@@ -188,6 +188,9 @@
                 path.concat(k), 'remove');
             this._updateAddRemoveObj(addRemoveObj,
                 path.concat(k), 'add', obj[k]);
+          } else if (obj[k].added) {
+            this._updateAddRemoveObj(addRemoveObj,
+                path.concat(k), 'add', obj[k]);
           }
           this._recursivelyUpdateAddRemoveObj(obj[k], addRemoveObj,
               path.concat(k));
diff --git a/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor.js b/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor.js
index de33fa1..a3b0272 100644
--- a/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor.js
+++ b/polygerrit-ui/app/elements/admin/gr-rule-editor/gr-rule-editor.js
@@ -196,6 +196,9 @@
     },
 
     _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;